Java面試題 史上最全的中高級JAVA工程師-面試題彙總

原文鏈接:https://blog.csdn.net/shengqianfeng/article/details/102572691
原創

史上最全的中高級JAVA工程師-面試題彙總

想了解博主本人,請閱讀《成就一億技術人,我在CSDN的這九年》

文章目錄

緩存

memcache的分佈式原理

memcached 雖然稱爲 “ 分佈式 ” 緩存服務器,但服務器端並沒有 “ 分佈式 ” 功能。每個服務器都是完全獨立和隔離的服務。 memcached 的分佈式,則是完全由客戶端程序庫實現的。 這種分佈式是 memcached 的最大特點。

memcache的內存分配機制

如何存放數據到memcached緩存中?(memcache內存分配機制)

Slab Allocator內存分配機制
預先將內存分配成數個slab倉庫,每個倉庫再切出不同大小的chunk,去適配收到的數據。多餘的只能造成浪費,不可避免。
增長因子(Grace factor):一般而言觀察數據大小的變化規律設置合理的增長因子,默認1.25倍.
太大容易造成浪費。memcached.exe -m 64 -p 11211 -f 1.25

如果有100byte的內容要存儲,但122大小的倉庫的chunk用滿了怎麼辦?
答:是並不會尋找更大倉庫的chunk來存儲,而是把122倉庫中的舊數據踢掉!

memcache的惰性失效機制

1 當某個值過期後並不會從內存刪除。(因此status統計時的curr_items有其信息)
2 如果之前沒有get過,將不會自動刪除。
如果(過期失效,沒get過一次)又沒有一個新值去佔用他的位置時,當做空的chunk佔用。
3 當取其值(get)時,判斷是否過期:如果過期返回空,且清空。(所以curr_items就減少了)
即這個過期只是讓用戶看不到這個數據而已,並沒有在過期的瞬間立即從內存刪除,這個過程
稱爲lazy expirtion,屬性失效,好處是節約了cpu和檢測的成本,稱爲“惰性失效機制”

memcache緩存的無底洞現象

緩存的無底洞現象
facebook的工作人員反應,他們在2010年左右,memcacahed節點就已經達到3000個,大約數千G的緩存,他們發現一個問題,memchache連接頻率太高導致效率下降,於是加memcache節點,添加後發現連接頻率導致的問題仍然沒有好轉,稱之爲“無底洞現象”。

問題分析
以用戶爲例:user-133-age,user-133_name,user-133-height…N個key
當服務器增多,133號用戶的信息也被散落在更多的服務器,
所以同樣是訪問個人主頁,得到相同的個人信息,節點越多,要連接節點越多,對於memcache的連接數並沒有隨着節點的增多而降低,問題出現。

事實上
nosql和傳統的rdbms並不是水火不容,兩者在某些設計上是可以相互參考的。
對於nosql的key-value這種存儲,key的設計可以參考mysql中表和列的設計。
比如user表下有age、name、height列,對應的key可以用user:133:age=23,user:133:name=ls,user:133:height=168;

問題的解決方案
把某一組key按其共同前綴來分佈,比如:user:133:age=23,user:133:name=ls,user:133:height=168;
在用分佈式算法求其節點時,應該以user:133來計算,而不是以user:133:age來計算,這樣這三個關於個人信息的key都落在同一個節點上。
再次訪問只需要連接一個節點。問題解決。

一致性Hash算法的實現原理

Hash環

我們把232次方想成一個環,比如鐘錶上有60個分針點組成一個圓,那麼hash環就是由232個點組成的圓。第一個點是0,最後一個點是232-1,我們把這232個點組成的環稱之爲HASH環。
在這裏插入圖片描述

一致性Hash算法

將memcached物理機節點通過Hash算法虛擬到一個虛擬閉環上(由0到232構成),key請求的時候通過Hash算法計算出Hash值然後對232取模,定位到環上順時針方向最接近的虛擬物理節點就是要找到的緩存服務器。

假設有ABC三臺緩存服務器:
我們使用這三臺服務器各自的IP進行hash計算然後對2~32取模即:
           Hash(服務器IP)%2~32
計算出來的結果是0到2~32-1的一個整數,那麼Hash環上必有一個點與之對應。比如:
在這裏插入圖片描述
在這裏插入圖片描述
現在緩存服務器已經落到了Hash環上,接下來我們就看我們的數據是怎麼放到緩存服務器的?
我們可以同樣對Object取Hash值然後對2~32取模,比如落到了接近A的一個點上:
在這裏插入圖片描述
那麼這個數據理應存到A這個緩存服務器節點上
在這裏插入圖片描述
所以,在緩存服務器節點數量不變的情況下,緩存的落點是不會變的。
在這裏插入圖片描述
但是如果B掛掉了呢?
按照hash且取模的算法,圖中3這個Object理應就分配到了C這個節點上去了,所以就會到C上找緩存數據,結果當然是找不到,進而從DB讀取數據重新放到了C上。
在這裏插入圖片描述
但是對於編號爲1,2的Object還是落到A,編號爲4的Object還是落到C,B宕機所影響的僅僅是3這個Object。這就是一致性Hash算法的優點。

Hash環的傾斜

前面我們理想化的把三臺memcache機器均勻分到了Hash環上:
在這裏插入圖片描述
但是現實情況可能是:
在這裏插入圖片描述
如果Hash環傾斜,即緩存服務器過於集中將會導致大量緩存數據被分配到了同一個服務器上。比如編號1,2,3,4,6的Object都被存到了A,5被存到B,而C上竟然一個數據都沒有,這將造成內存空間的浪費。
爲了解決這個問題,一致性Hash算法中使用“虛擬節點”解決。
在這裏插入圖片描述

虛擬節點解決Hash環傾斜

在這裏插入圖片描述
“虛擬節點”是“實際節點”在hash環上的複製品,一個實際節點可能對應多個虛擬節點。這樣就可以將ABC三臺服務器相對均勻分配到Hash環上,以減少Hash環傾斜的影響,使得緩存被均勻分配到hash環上。

hash算法平衡性

  平衡性指的是hash的結果儘可能分佈到所有的緩存中去,這樣可以使得所有的緩存空間都可以得到利用。但是hash算法不保證絕對的平衡性,爲了解決這個問題一致性hash引入了“虛擬節點”的概念。虛擬節點”( virtual node )是實際節點在 hash 空間的複製品( replica ),一實際個節點對應了若干個“虛擬節點”,這個對應個數也成爲“複製個數”,“虛擬節點”在 hash 空間中以 hash 值排列。“虛擬節點”的hash計算可以採用對應節點的IP地址加數字後綴的方式。
  例如假設 cache A 的 IP 地址爲202.168.14.241 。
  引入“虛擬節點”前,計算 cache A 的 hash 值: Hash(“202.168.14.241”);
  引入“虛擬節點”後,計算“虛擬節”點 cache A1 和 cache A2 的 hash 值:
    Hash(“202.168.14.241#1”); // cache A1
    Hash(“202.168.14.241#2”); // cache A2
  這樣只要是命中cacheA1和cacheA2節點,就相當於命中了cacheA的緩存。這樣平衡性就得到了提高。
  參考:https://www.cnblogs.com/yixiwenwen/p/3580646.html

memcached與redis的區別

1 redis做存儲,可以持久化,memcache做緩存,數據易丟失。
2 redis支持多數據類型,memcache存放字符串。
3 redis服務端僅支持單進程、單線程訪問,也就是先來後到的串行模式,避免線程上下文切換,自然也就保證數據操作的原子性。Memcache服務端是支持多線程訪問的。
4 redis雖然是單進程單線程模式,但是redis使用了IO多路複用技術做到一個線程可以處理很多個請求來保證高性能。

Redis的主從複製

1 在Slave啓動並連接到Master之後,它將主動發送一個SYNC命令給Master。
2 Master在收到SYNC命令之後,將執行BGSAVE命令執行後臺存盤進程(rdb快照), 同時收集所有接收到的修改數據集的命令即寫命令到緩衝區,在後臺存盤進程執行完畢後,Master將傳送整個數據庫文件到Slave。
3 Slave在接收到數據庫文件數據之後,將自身內存清空,加載rdb文件到內存中完成一次完全同步。
4 接着,Master繼續將所有已經收集到緩衝區的修改命令,和新的修改命令依次傳送給Slaves
5 Slave將在本地執行這些數據修改命令,從而達到最終的數據同步
6 之後Master和Slave之間會不斷通過異步方式進行命令的同步,從而保證數據的實時同步
7 如果Master和Slave之間的鏈接出現斷連現象,Slave可以自動重連Master,但是在
重新連接成功之後:
2.8之前的redis將進行一次完全同步
2.8之後進行部分同步,使用的是PSYNC命令
如下:

Redis的部分複製過程

部分同步工作原理如下:
1):Master爲被髮送的複製流創建一個內存緩衝區(in-memory backlog),記錄最近發送的複製流命令
2):Master和Slave之間都記錄一個複製偏移量(replication offset)和當前Master ID(Master run id)
3):當出現網絡斷開,Slave會重新連接,並且向Master請求繼續執行原來的複製進程
4):如果Slave中斷網前的MasterID和當前要連的MasterID相同,並且從斷開時到當前時刻Slave記錄的偏移量所指定的數據仍然保存在Master的複製流緩衝區裏面,則Master會向Slave發送缺失的那部分數據,Slave執行後複製工作可以繼續執行。
5):否則Slave就執行完整重同步操作

Redis的主從複製阻塞模式

1 同一個Master服務可以同步n多個Slave服務
2 Slave節點同樣可以接受其它Slave節點的連接和同步服務請求,分擔Master節點的同步壓力
3 Master是以非阻塞方式爲Slave提供同步服務,所以主從複製期間Master一樣可以提供讀寫請求。
4 Slave同樣是以非阻塞的方式完成數據同步,在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的數據
  • 1
  • 2
  • 3
  • 4

Redis的數據持久化方式

Rdb快照和aof
RDB快照:可以配置在n秒內有m個key修改就做自動化快照方式
AOF:每一個收到的寫命令都通過write函數追加到文件中。更安全。

Redis的高可用部署方式

哨兵模式

redis3.0之前的Sentinel哨兵機制,redis3.0之前只能使用一致性hash方式做分佈式緩存。哨兵的出現主要是解決了主從複製出現故障時需要人爲干預的問題。

Redis哨兵主要功能

(1)集羣監控:負責監控Redis master和slave進程是否正常工作
(2)消息通知:如果某個Redis實例有故障,那麼哨兵負責發送消息作爲報警通知給管理員
(3)故障轉移:如果master node掛掉了,會自動轉移到slave node上
(4)配置中心:如果故障轉移發生了,通知client客戶端新的master地址

Redis哨兵的高可用

原理:當主節點出現故障時,由Redis Sentinel自動完成故障發現和轉移,並通知應用方,實現高可用性
在這裏插入圖片描述

哨兵機制建立了多哨兵節點,共同監控數據節點的運行狀況。
同時哨兵節點之間也互相通信,交換對主從節點的監控狀況。
每隔1秒每個哨兵會向整個集羣:Master主服務器+Slave從服務器+其他Sentinel(哨兵)進程,發送一次ping命令做一次心跳檢測。

哨兵如何判斷redis主從節點是否正常?

涉及兩個新的概念:主觀下線和客觀下線。

  1. 主觀下線:一個哨兵節點判定主節點down掉是主觀下線。
  2. 客觀下線:只有半數哨兵節點都主觀判定主節點down掉,此時多個哨兵節點交換主觀判定結果,纔會判定主節點客觀下線。

原理:基本上哪個哨兵節點最先判斷出這個主節點客觀下線,就會在各個哨兵節點中發起投票機制Raft算法(選舉算法),最終被投爲領導者的哨兵節點完成主從自動化切換的過程。

集羣模式

  redis3.0之後的容錯集羣方式,無中心結構,每個節點保存數據和整個集羣狀態,每個節點都和其他所有節點連接,需要至少三個master提供寫的功能。
  因此集羣中至少應該有奇數個節點,因此至少有三個節點,每個節點至少有一個備份節點,所以redis集羣應該至少6個節點。
  每個Master有一個範圍的slot槽位用於寫數據。

Redis可以在線擴容嗎?zk呢

  Reids的在線擴容,不需要重啓服務器,動態的在原始集羣中添加新的節點,並分配slot槽。
但是zk不能在線擴容,需要重啓,但是我們可以選擇一個一個重啓。

Redis高併發和快速的原因

1.redis是基於內存的,內存的讀寫速度非常快;
2.redis是單線程的,省去了很多上下文切換線程的時間;
3.redis使用多路複用技術,可以處理併發的連接。
缺點:無法發揮多核CPU性能
  • 1
  • 2
  • 3
  • 4

瀏覽器本地緩存的瞭解和使用

資源在瀏覽器端的本地緩存可以通過Expires和Last-Modified返回頭信息進行有效控制。
  • 1

1)Expires告訴瀏覽器在該指定過期時間前再次訪問同一URL時,直接從本地緩存讀取,無需再向服務器發起http請求;
  優點是:瀏覽器直接讀取緩存信息無需發起http請求。
   缺點是:當用戶按F5或Ctl+F5刷新頁面時瀏覽器會再次發起http請求。

2)當服務器返回設置了Last-Modified頭,下次發起同一URL的請求時,請求頭會自動包含If-Modified-Since頭信息,服務器對靜態內容會根據該信息跟文件的最後修改時間做比較,如果最後修改時間不大於If-Modified-Since頭信息,則返回304:告訴瀏覽器請求內容未更新可直接使用本地緩存。
(注意:只對靜態內容有效,如js/css/image/html等,不包括動態內容,如JSP)
優點:無論用戶行爲如何都有效;
缺點:仍需向服務器發起一次http請求;

緩存雪崩

如果緩存集中在一段時間內失效,發生大量的緩存穿透,所有的查詢都落在數據庫上,造成了緩存雪崩。

解決辦法:
沒有完美的解決方案,可以通過隨機算法讓失效時間隨機分佈,避免同一時刻失效。

緩存穿透

訪問一個不存在的key,緩存不起作用,請求會穿透到DB,可能DB也沒查到,流量大時DB會掛掉。

解決辦法:
1.採用布隆過濾器,使用一個足夠大的bitmap,用於存儲可能訪問的key,不存在的key直接被過濾;
2訪問key未在DB查詢到值,也將空值寫進緩存,但可以設置較短過期時間。

HashMap

HashMap的Hash碰撞

在這裏插入圖片描述
  Hash值衝突問題是Hash表存儲模型需要解決的一個問題。通常有兩種方法:
  將相同Hash值的Entry對象組織成一個鏈表放置在hash值對應的槽位。HashMap採用的是鏈表法,且是單向鏈表(通過head元素就可以操作後續所有元素,對鏈表而言,新加入的節點會從頭節點加入。)
核心源碼:

private void addEntry(int hash, K key, V value, int bucketIndex) {  
    Entry<K,V> e = table[bucketIndex];  
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
    if (size++ >= threshold)  
        resize(2 * table.length);  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以上代碼說明:
系統總是將新添加的 Entry 對象放入 table 數組的 bucketIndex 索引處。
1 如果 bucketIndex 索引處已經有了一個 Entry 對象,那新添加的 Entry 對象指向原有的 Entry 對象
(產生一個 Entry 鏈)
2 如果 bucketIndex 索引處沒有 Entry 對象,也就是上面程序代碼的 e 變量是 null,也就是新放入的
Entry 對象指向 null,也就是沒有產生 Entry 鏈。
HashMap裏面沒有出現hash衝突時,沒有形成單鏈表時,hashmap查找元素很快,get()方法能夠直接定位到元素,
但是出現單鏈表後,單個bucket 裏存儲的不是一個 Entry,而是一個 Entry 鏈,系統只能必須按順序遍歷每個
Entry,直到找到想搜索的 Entry 爲止——如果恰好要搜索的 Entry 位於該 Entry 鏈的最末端(該 Entry 是最早
放入該 bucket 中),那系統必須循環到最後才能找到該元素。

HashMap的get和put原理

PUT原理
當調用HashMap的put方法傳遞key和value時,先調用key的hashcode方法。
通過key的Hash值來找到Bucket----‘桶’的位置,然後迭代這個位置的Entry列表
判斷是否存在key的hashcode和equals完全相同的key,如果完全相同則覆蓋value,
否則插入到entry鏈的頭部。

HashMap在put時的Entry鍊形成的場景

當程序試圖將一個key-value對放入HashMap中時,程序首先根據該 key 的 hashCode() 返回值決定該 Entry 的存儲位置:
如果這兩個 Entry 的 key 的 hashCode() 返回值相同,那它們的存儲位置相同。
如果這兩個 Entry 的 key 通過 equals 比較返回 true,新添加 Entry 的 value 將覆蓋集合中原有 Entry 的 value,但key不會覆蓋。
  • 1
  • 2
  • 3

如果這兩個 Entry 的 key 通過 equals 比較返回 false,新添加的 Entry 將與集合中原有 Entry 形成 Entry 鏈,而且新添加的 Entry 位於 Entry 鏈的頭部

GET原理
根據該 key 的 hashCode 值計算它的 hash 碼,遍歷並循環取出 Entry 數組中指定索引處的Entry值,如果該 Entry 的 key 與被搜索 key 相同 ,且Enrty的hash值跟key的hash碼相同,然後看是否是Entry鏈,如果是則迭代這個位置的Entry列表,判斷是否存在key的hashcode和equals完全相同的key,如果完全相同則獲取value。

HashMap的rehash

  HashMap初始容量大小爲16,一般來說,當有數據要插入時,都會檢查容量有沒有超過設定的thredhold,如果超過,需要增大Hash表的尺寸,但是這樣一來,整個Hash表裏的元素都需要被重算一遍。這叫rehash,這個成本相當的大

HashMap的線程不安全問題

  比如put操作時,有兩個線程A和B,首先A希望插入一個key-value對到HashMap中,首先計算記錄所要落到的桶的索引BucketIndex座標,然後獲取到該桶裏面的Entry鏈表header頭結點,此時線程A的時間片用完了,而此時線程B被調度得以執行,和線程A一樣執行,只不過線程B成功將記錄插到了桶裏面,假設線程A插入的記錄計算出來的桶索引和線程B要插入的記錄計算出來的桶索引是一樣的,那麼當線程B成功插入之後,線程A再次被調度運行時,它依然持有過期的鏈表頭但是它對此一無所知,以至於它認爲它應該這樣做,如此一來就覆蓋了線程B插入的記錄,這樣線程B插入的記錄就憑空消失了,造成了數據不一致的行爲。另一個不安全的體現是是get操作可能由於resize而死循環。

參考:https://www.cnblogs.com/qiumingcheng/p/5259892.html
在這裏插入圖片描述

HashMap和Hashtable的區別

相同點
1 都實現了Map接口
2 Hashtable和HashMap採用的hash/rehash算法都大概一樣,所以性能不會有很大的差異

不同點
1 hashMap允許NULL作爲key和value,而hashtable不允許
2 hashMap線程不安全,Hashtable線程安全
3 hashMap速度快於hashtable
4 HashMap 把 Hashtable的contains方法去掉了,改成containsvalue和containsKey,避免引起誤會
5 Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現

爲什麼collection沒有實現clonable接口

Collection接口有很多不同的集合實現形式,而clonable只對具體的對象有意義。

爲什map沒有實現collection接口

Set 和List 都繼承了Conllection,Map沒有繼承於Collection接口,Map提供的是key-Value的映射,而Collection代表一組對象。

Map接口的實現有哪些,區別是什麼

HashMap,LinkedHashMap,Hashtable,TreeMap。

LinkedHashMap 是HashMap的一個子類,保存了記錄的插入順序
Hashtable和HashMap類似,它繼承自Dictionary類,不同的是它不允許鍵或值爲空。
TreeMap實現SortMap接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器

線程池

Executors框架的四種線程池及拒絕策略

四種線程池

ExecutorService executorService =
固定大小線程池

Executors.newFixedThreadPool(60);
設置固定值會造成高併發線程排隊等待空閒線程,尤其是當讀取大數據量時線程處理時間長而不釋放線程,導致無法創建新線程。

可緩存線程池
Executors.newCachedThreadPool();
線程池無限大,而系統資源(內存等)有限,會導致機器內存溢出OOM。

定長且可定時、週期線程池
Executors.newScheduledThreadPool(5);

單線程線程池
Executors.newSingledThreadPool();

/* 自定義線程池。
		 * 構造參數:
		 * public ThreadPoolExecutor(
			 * int corePoolSize,--當前線程池核心線程數
			 * int maximumPoolSize,--當前線程池最大線程數
			 * long keepAliveTime,--保持活着的空間時間
			 * TimeUnit unit,--時間單位
			 * BlockingQueue<Runnable> workQueue,--排隊等待的自定義隊列
			 * ThreadFactoty threadFactory,
			 * RejectedExecutionHandler handler--隊列滿以後,其他任務被拒絕執行的方法
		 * ){.........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在使用有界隊列時,若有新的任務需要執行,

  • 若線程池實際線程數小於corePoolSize,則優先創建線程,
  • 若大於corePoolSize,則會將任務加入隊列,
  • 若隊列已滿,則在總線程數不大於maximumPoolSize的前提下,創建新的線程,
  • 若線程數大於maximumPoolSize,則執行拒絕策略。或其他自定義方式。

JDK拒絕策略

  • AbortPolicy:默認,直接拋出異常,系統正常工作。
  • DiscardOldestPolicy:丟棄最老的一個請求,嘗試再次提交當前任務。
  • CallerRunsPolicy:只要線程池未關閉,該策略直接在調用者線程中,運行當前被丟棄的任務。用線程池中的線程執行,而是交給調用方來執行, 如果添加到線程池失敗,那麼主線程會自己去執行該任務,不會等待線程池中的線程去執行
new ThreadPoolExecutor(   
   2, 3, 30, TimeUnit.SECONDS,    
    new SynchronousQueue<Runnable>(),    
    new RecorderThreadFactory("CookieRecorderPool"),    
     new ThreadPoolExecutor.CallerRunsPolicy());  
  • 1
  • 2
  • 3
  • 4
  • 5
  • DiscardPolicy:丟棄無法處理的任務,不給予任何處理。
  • 自定義拒絕策略
    如果需要自定義策略,可以實現RejectedExecutionHandler接口。

Reactor模式

參考:https://www.cnblogs.com/duanxz/p/3696849.html

Reactor單線程模型

在這裏插入圖片描述
在這裏插入圖片描述
一個Acceptor線程,監聽Accept事件,負責接收客戶端的連接SocketChannel,SocketChannel註冊到Selector上並關心可讀可寫事件。
一個Reactor線程,負責輪訓selector,將selector註冊的就緒事件的key讀取出來,拿出attach任務Handler根據事件類型分別去執行讀寫等。

單線程模型的瓶頸
比如:拿一個客戶端來說,進行多次請求,如果Handler中數據讀出來後處理的速度比較慢(非IO操作:解碼-計算-編碼-返回)會造成客戶端的請求被積壓,導致響應變慢!
所以引入Reactor多線程模型!

Reactor多線程模型

在這裏插入圖片描述
在這裏插入圖片描述

Reactor多線程就是把Handler中的IO操作,非IO操作分開。
操作IO的線程稱爲IO線程,操作非IO的線程叫做工作線程
客戶端的請求(IO操作:讀取出來的數據)可以直接放進工作線程池(非IO操作:解碼-計算-編碼-返回)中,這樣異步處理,客戶端發送的請求就得到返回了不會一直阻塞在Handler中。
但是當用戶進一步增加的時候,Reactor線程又會出現瓶頸,因爲Reactor中既有IO操作,又要響應連接請求。爲了分擔Reactor的負擔,所以引入了主從Reactor模型!

主從Reactor模型

在這裏插入圖片描述
在這裏插入圖片描述
  主Reactor用於響應連接請求,從Reactor用於處理IO操作請求!
  特點是:服務端用於接收客戶端連接的不再是1個單獨的NIO線程(Acceptor線程),而是一個獨立的NIO線程池。
  Acceptor線程池接收到客戶端TCP連接請求處理完成後(可能包含接入認證等),將新創建的SocketChannel註冊到I/O線程池(sub reactor線程池)的某個I/O線程上,由它負責SocketChannel的讀寫和編解碼工作。
  Acceptor線程池只用於客戶端的登錄、握手和安全認證,一旦鏈路建立成功,就將鏈路註冊到後端subReactor線程池的I/O線程上,有I/O線程負責後續的I/O操作。
  第三種模型比起第二種模型,是將Reactor分成兩部分,mainReactor負責監聽server socket,accept新連接,並將建立的socket分派給subReactor。subReactor負責多路分離已連接的socket,讀寫網 絡數據,對業務處理功能,其扔給worker線程池完成。通常,subReactor個數上可與CPU個數等同。

JVM

Object的內存佈局

在這裏插入圖片描述

方法區卸載Class的條件

1 該類所有的實例已經被回收
2 加載該類的ClassLoader已經被回收
4該類對應的java.lang.Class對象沒有任何地方被引用

Ps:方法區除了回收無用class,也回收廢棄常量,即沒有被引用常量

可以作爲GC Roots的對象包括哪些

虛擬機棧(棧幀中的局部變量表)中引用的變量
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI引用的變量

JVM運行時內存模型

方法區、堆、虛擬機棧、本地方法棧、程序計數器

Netty的ByteBuffer的引用計數器機制

從netty的4.x版本開始,netty使用引用計數機制進行部分對象的管理,通過該機制netty可以很好的實現自己的共享資源池。
如果應用需要一個資源,可以從netty自己的共享資源池中獲取,新獲取的資源對象的引用計數被初始化爲1,可以通過資源對象的retain方法增加引用計數,當引用計數爲0的時候該資源對象擁有的資源將會被回收。

判斷對象是否存活的兩種方法

1 引用計數法:缺點是對循環引用的對象無法回收
2 可達性分析

Java對象的初始化過程

在這裏插入圖片描述

類加載雙親委派模型

從上到下分三個類加載器:

BootStrap classloader:啓動類加載器,負責將Java_HOME/lib下的類庫加載到虛擬機內存中,比如rt.jar
Extension classloader:擴展類加載器,負責將JAVA_HOME/lib/ext下的類庫加載到虛擬機內存中。
Application classloader:應用程序類加載器,負責加載classpath環境變量下指定的類庫。如果程序中沒有自定義過類加載器,那麼這個就是程序中默認的類加載器。

雙親委派模型:

  如果一個類加載器收到類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器完成。每個類加載器都是如此,只有當父加載器在自己的搜索範圍內找不到指定的類時(即ClassNotFoundException),子加載器纔會嘗試自己去加載。
在這裏插入圖片描述
防止自定義的一些跟jdk標準庫中衝突的全限定名的類被加載,導致標準庫函數不可用。

Zookeeper

Zookeeper的常用應用場景有哪些

  • 分佈式鎖:獲取父節點下的最小節點作爲獲得鎖的一方
  • 命名服務:通過在zookeeper節點下創建全局唯一的一個path
  • 配置管理:配置放在zk上,所有應用監聽節點改變。
  • 集羣管理:GroupMembers集羣管理,是否有機器退出和加入

Zookeeper的分佈式數據一致性算法

ZAB原子消息廣播協議

一種是基於basic paxos實現的,另外一種是基於fast paxos算法實現的。

參考:
http://www.360doc.com/content/16/0823/11/14513665_585293946.shtml
ZAB協議定義了選舉(election)、發現(discovery)、同步(sync)、廣播(Broadcast)四個階段;

Zk啓動過程的Leader選舉分析及數據同步

參考:http://www.cnblogs.com/leesf456/p/6107600.html

Zookeeper數據同步的簡單描述

  在ZooKeeper中所有的客戶端事務請求都由一個主服務器也就是Leader來處理,其他服務器爲Follower,Leader將客戶端的事務請求轉換爲事務Proposal,並且將Proposal分發給集羣中其他所有的Follower,然後Leader等待Follwer反饋,當有過半數(>=N/2+1)的Follower反饋信息後,Leader將再次向集羣內Follower廣播Commit信息,Commit爲將之前的Proposal提交;

ZK集羣最少需要幾臺機器?

三臺,2N+1,保證奇數,主要是爲了leader選舉算法中的“超過半數有效(>=N/2+1)”

Zookeeper和Eureka的區別

:ZK保證Cp,即一致性,分區容錯性,比如當master節點因爲網絡故障和其他節點失去聯繫的時候,剩餘節點會重新進行Master選舉。問題在於Master選舉的時間太長30~210s,選舉期間整個zk集羣是不可用的,這就導致選舉期間的註冊服務癱瘓。
  Eureka保證Ap,高可用性,它沒有所謂主從節點概念,各節點平等。某節點掛掉不影響其他節點功能,其他節點照樣提供查詢和註冊功能。Eureka客戶端發現Eureka節點掛掉直接切換到其他正常的節點上去。只不過可能查到的數據不是最新的,也就是Eureka不保證數據的強一致性。
  作爲註冊中心,推薦Eureka,因爲註冊服務更重要的是可用性。

Mysql

InnoDB和MyISAM存儲引擎的區別

Starting from MySQL 5.5.5, the default storage engine for new tables isInnoDB rather than MyISAM.
在這裏插入圖片描述

Btree索引和Hash索引的區別

Btree索引適合範圍查找,Hash索引適合精確查找

數據庫的ACID特性

數據庫事務必須具備ACID特性
原子性:Atomic,所有的操作執行成功,纔算整個事務成功
一致性:Consistency,不管事務success或fail,不能破壞關係數據的完整性以及業務邏輯上的一致性
隔離性:Isolation,每個事務擁有獨立數據空間,多個事務的數據修改相互隔離。事務查看數據更新時,數據要麼是另一個事務修改前的狀態,要麼是修改後狀態,不應該查看到中間狀態數據。
持久性:Durability,事務執行成功,數據必須永久保存。重啓DB,數據需要恢復到事務執行成功後的狀態。
原子性、一致性、持久性DBMS通過日誌來實現。
  隔離性DBMS通過鎖來實現

Mysql數據庫的隔離級別

M
在這裏插入圖片描述

Select For Update使用場景

  select for update 的使用場景,爲了避免自己看到的數據並不是數據庫存儲的最新數據並且看到的數據只能由自己修改,需要用 for update 來限制。

分佈式事務模型之XA和TCC的區別和聯繫?

XA-DTP模型

  最早的分佈式事務模型是 X/Open 國際聯盟提出的 X/Open Distributed Transaction Processing(DTP)模型,也就是大家常說的 X/Open XA 協議,簡稱XA 協議。
  DTP 模型中包含一個全局事務管理器(TM,Transaction Manager)和多個資源管理器(RM,Resource Manager)。全局事務管理器負責管理全局事務狀態與參與的資源,協同資源一起提交或回滾;資源管理器則負責具體的資源操作。

TCC模型

TCC(Try-Confirm-Cancel)分佈式事務模型相對於 XA 等傳統模型,其特徵在於它不依賴資源管理器(RM)對分佈式事務的支持,而是通過對業務邏輯的分解來實現分佈式事務。
Try-Confirm-Cancel
Try 操作對應2PC 的一階段準備(Prepare);Confirm 對應 2PC 的二階段提交(Commit),Cancel 對應 2PC 的二階段回滾(Rollback),可以說 TCC 就是應用層的 2PC。

參考
https://mp.weixin.qq.com/s?__biz=MzUzMzU5Mjc1Nw==&mid=2247483681&idx=1&sn=05845495c5ef33683addd98fffc72106&chksm=faa0eefbcdd767edbf46cea6f223b426e276dd4d9b19cce64f59387590818f5e4eb96c7d2533&mpshare=1&scene=2&srcid=0118GSYShGZaOyCndUoAqsae&from=timeline#rd

Mysql-binlog日誌複製方式

①基於段的複製
記錄的是執行的語句
②基於行的複製
記錄是表中每一行的操作
③混合複製

mysql主從複製原理

在這裏插入圖片描述
從服務器的IO線程讀取主服務器的二進制日誌變更,寫入到中繼日誌relaylog中,如果IO線程追趕上了主服務器的日誌,則進入sleep狀態,直到主服務器發送喚醒信號,從服務器上的SQL線程重放relaylog中的日誌。

基於日誌點的複製和GTID的複製有何區別?

基於日誌點的複製:從主服務器的哪個二進制日誌的偏移量進行增量同步,如果指定錯誤會造成遺漏或重複。
基於GTID的複製:從服務器會告訴主服務器,已經在從服務器上已經執行完了哪些gtid值,然後主庫會把從庫未執行的事務gtid值發送給從庫執行。同一個事務只在指定的從庫上執行一次。

Mysql性能診斷和優化

聚簇索引和非聚簇索引的區別

聚簇索引,就是指主索引文件和數據文件爲同一份文件,聚簇索引主要用在Innodb存儲引擎中。如主鍵。B+Tree的葉子節點上的data就是數據本身。
非聚簇索引就是指B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址

消息隊列

消費者宕機:怎麼保證消息隊列消息不丟失?

  比如activemq或者rabbitmq生產者消息投遞到消息隊列後,消費者拿到消息後,默認是自動簽收機制,消息隊列將刪除這條消息,但是如果僅僅是拿到但是沒有來得及處理業務邏輯時,消費者就宕機,那麼此消息將會丟失,以後也不會再收到。
解決辦法
  消費端要設置簽收機制爲手動簽收,只有當消息最終被處理,才告訴消息隊列已經消費,此時消息隊列再刪除這條消息。

MQ集羣宕機:怎麼保證消息不丟失?

  生產者投遞消息到mq服務器,如果不保證消息和隊列的持久化,那麼當mq宕機時消息將徹底丟失,所以需要對消息做持久化存儲,可以存儲到磁盤或者數據庫中,當mq服務器恢復時,消費端可以繼續消費mq服務器中的消息。

  但是,比如RabbitMQ的消息持久化,是不承諾100%的消息不丟失的!
 &emsp**;原因**:因爲有可能RabbitMQ接收到了消息,但是還沒來得及持久化到磁盤,他自己就宕機了,這個時候消息還是會丟失的。如果要完全100%保證寫入RabbitMQ的數據必須落地磁盤,不會丟失,需要依靠其他的機制。

參考:
https://mp.weixin.qq.com/s/ZAWPRToPQFcwzHBf47jZ-A
https://mp.weixin.qq.com/s/HwAc6o8jdIHQTnE3ghXhIA
https://mp.weixin.qq.com/s/AEn3j2lVJOHZx9yegwTsvw
https://mp.weixin.qq.com/s/uqWIf0MAet_StszuOrZCwQ
https://mp.weixin.qq.com/s/9SFrwaCCLnNyuCqP_KQ0zw
https://mp.weixin.qq.com/s/vZ4KVC2eGmssnQUyIKgzfw
https://mp.weixin.qq.com/s/r2_o5wa6Gn94NY4ViRnjpA

Spring源碼系列

springmvc如何解決循環依賴的問題

  當使用構造器方式初始化一個bean,而且此時多個Bean之間有循環依賴的情況,spring容器就會拋出異常!
解決辦法:初始化bean的時候(注意此時的bean必須是單例,否則不能提前暴露一個創建中的bean)使用set方法進行注入屬性,此時bean對象會先執行構造器實例化,接着將實例化後的bean放入一個map中,並提供引用。當需要通過set方式設置bean的屬性的時候,spring容器就會從map中取出被實例化的bean。比如A對象需要set注入B對象,那麼從Map中取出B對象即可。以此類推,不會出現循環依賴的異常。

spring事務的傳播行爲和隔離級別

spring事務七個事務傳播行爲

在TransactionDefinition接口中定義了七個事務傳播行爲:

  • PROPAGATION_REQUIRED 如果存在一個事務,則支持當前事務。如果沒有事務則開啓一個新的事務。
  • PROPAGATION_SUPPORTS 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行。但是對於事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
  • PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。
  • PROPAGATION_REQUIRES_NEW 總是開啓一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。
  • PROPAGATION_NOT_SUPPORTED 總是非事務地執行,並掛起任何存在的事務。
  • PROPAGATION_NEVER 總是非事務地執行,如果存在一個活動事務,則拋出異常
  • PROPAGATION_NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行

Spring事務的五種隔離級別

在TransactionDefinition接口中定義了五個不同的事務隔離級別

  • ISOLATION_DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.
    另外四個與JDBC的隔離級別相對應
  • ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的數據。這種隔離級別會產生髒讀,不可重複讀和幻像讀
  • ISOLATION_READ_COMMITTED 保證一個事務修改的數據提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀。
  • ISOLATION_REPEATABLE_READ 這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重複讀)。
  • ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理爲順序執行。除了防止髒讀,不可重複讀外,還避免了幻像讀。

設計模式

單例模式

1懶漢模式-非安全
懶漢模式(線程不安全,可能出現多個Singleton 實例)

public class Singleton { 
    private static Singleton instance; 
    private Singleton (){} 
<span class="token keyword">public</span> <span class="token keyword">static</span> Singleton <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> 
		<span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span> 
       instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
		<span class="token punctuation">}</span> 
		<span class="token keyword">return</span> instance<span class="token punctuation">;</span> 
<span class="token punctuation">}</span> 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2懶漢模式-安全
懶漢模式 (線程安全)

public class Singleton { 
    private static Singleton instance; 
private Singleton (){} 
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> Singleton <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> 
		<span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span> 
    	 instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
		<span class="token punctuation">}</span> 
		<span class="token keyword">return</span> instance<span class="token punctuation">;</span> 
<span class="token punctuation">}</span> 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3餓漢模式

public class Singleton { 
    private static Singleton instance = new Singleton(); 
    private Singleton (){} 
    public static Singleton getInstance() { 
         return instance; 
    } 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4餓漢模式(變種)
餓漢(變種,跟第三種差不多,都是在類初始化即實例化instance)

public class Singleton { 
    private Singleton instance = null; 
    static { 
    		instance = new Singleton(); 
    } 
    private Singleton (){} 
    public static Singleton getInstance() { 
    		return this.instance; 
    } 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

5靜態內部類
靜態內部類,跟三四有細微差別:
Singleton類被裝載instance不一定被初始化,因爲內部類SingletonHolder沒有被主動使用,只有顯示調用getInstance纔會顯示裝載SingletonHolder 類,從而實例化instance

public class Singleton { 
    private static class SingletonHolder { 
         private static final Singleton INSTANCE = new Singleton(); 
    } 
    private Singleton (){} 
    public static final Singleton getInstance() { 
         return SingletonHolder.INSTANCE; 
    } 
}   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6枚舉
枚舉(既可以避免多線程同步問題,還可以防止被反序列化重建對象)

public enum Singleton { 
    INSTANCE;
public void whateverMethod() {

}

public static void main(String[] args) {
Singleton s = Singleton.INSTANCE;
Singleton s2 = Singleton.INSTANCE;
System.out.println(s==s2);
}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

**輸出結果:**true
  說明這種方式創建的對象是同一個,因爲枚舉類中的INSTANCE是static final類型的,只能被實例化一次。對於Enum中每一個枚舉實例,都是相當於一個單獨的Singleton實例。所以借用 《Effective Java》一書中的話,
單元素的枚舉類型已經成爲實現Singleton的最佳方法

7懶漢升級版

public class Singleton { 
    private volatile static Singleton singleton; 
    private Singleton (){} 
    public static Singleton getSingleton() { 
    		if (singleton == null) { 
        		synchronized (Singleton.class) { 
        			if (singleton == null) { 
          			  	singleton = new Singleton(); 
       			 } 
        		} 
    		} 
    		return singleton; 
    	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

策略模式

在這裏插入圖片描述

JDK源碼

ThreadLocal的實現原理

ThreadLocal的實現原理,有什麼缺點?跟線程池結合使用要注意什麼
在這裏插入圖片描述
原理:Current Thread當前線程中有一個ThreadLocalMap對象,它的key是ThreadLocal的弱引用,Value是ThreadLocal調用set方法設置的對象值。每一個線程維護一個各自的ThreadLocalMap,所以多個線程之間變量相互隔離,互不干擾。

缺點:存在內存泄漏問題,因爲當ThreadLocal設置爲null後,ThreadLocalMap的key的弱引用指向了null,又沒有任何的強引用指向threadlocal,所以threadlocal會被GC回收掉。但是,ThreadLocalMap的Value不會被回收,CurrentThread當前線程的強引用指向了ThreadLocalMap,進而指向了這個Entry<key,value>,所以只有當currentThread結束強引用斷開後,currentThread、ThreadLocalMap、Entry將全部被GC回收。
所以結論是
  只要currentThread被GC回收,就不會出現內存泄漏。
但是在currentThread被GC回收之前,threadlocal設置爲null之後的這段時間裏,Value不會被回收,比如當使用線程池的時候,線程結束不會被GC回收,會被繼續複用,那這個Value肯定還會繼續存在。如果這個Value很大的情況下,可能就會內存泄漏。
雖然threadlocal的set和get方法執行時會清除key爲null的value,但是如果當前線程在使用中沒有調用threadlocal的set或者get方法一樣可能會內存泄漏。

跟線程池結合使用的注意事項
  因爲線程池中線程複用的情況,本次的threadlocal中可能已經存在數據,所以上一次使用完threadlocal的變量後,要調用threadlocal的remove方法清除value。而且要注意調用完remove後應該保證不會再調用get方法。

AQS實現公平鎖和非公平鎖

基於AQS的鎖(比如ReentrantLock)原理大體是這樣:

  •   有一個state變量,初始值爲0,假設當前線程爲A,每當A獲取一次鎖,status++. 釋放一次,status–.鎖會記錄當前持有的線程。
  •   當A線程擁有鎖的時候,status>0. B線程嘗試獲取鎖的時候會對這個status有一個CAS(0,1)的操作,嘗試幾次失敗後就掛起線程,進入一個等待隊列。
  •   如果A線程恰好釋放,–status==0, A線程會去喚醒等待隊列中第一個線程,即剛剛進入等待隊列的B線程,B線程被喚醒之後回去檢查這個status的值,嘗試CAS(0,1),而如果這時恰好C線程也嘗試去爭搶這把鎖。

非公平鎖實現
C直接嘗試對這個status CAS(0,1)操作,併成功改變了status的值,B線程獲取鎖失敗,再次掛起,這就是非公平鎖,B在C之前嘗試獲取鎖,而最終是C搶到了鎖。
公平鎖
C發現有線程在等待隊列,直接將自己進入等待隊列並掛起,B獲取鎖

RPC

RPC的序列化方式有哪些

Thrift—facebook
ProtoBuf—google
Hessian
JAVA原生的序列化接口
Json/xml

服務熔斷與服務降級概念

服務熔斷:

  一般指某個服務的下游服務出現問題時採用的手段,而服務降級一般是從整體層面考慮的。下游服務出現問題時可以進行服務熔斷。
  對於目標服務的請求和調用大量超時或失敗,這時應該熔斷該服務的所有調用,並且對於後續調用應直接返回,從而快速釋放資源,確保在目標服務不可用的這段時間內,所有對它的調用都是立即返回,不會阻塞的。再等到目標服務好轉後進行接口恢復。

服務降級:

  當服務器壓力劇增的情況下,根據當前業務情況及流量對一些服務和頁面有策略的降級,以此釋放服務器資源以保證核心任務的正常運行。

其他整理

ThreadLocalMap的線性探測法、HashMap的拉鍊法。兩種解決hash碰撞的方式有何不同?


Netty的RPC如何實現


Netty中源碼inbound和outbound有啥區別?


怎麼分庫分表可以做到多維度查找


Fork/Join框架


JAVA線程執行中怎麼kill掉

1 通過設置全局變量標誌來控制線程的任務執行完成.進而銷燬線程
2 如果線程處於長久的阻塞狀態,可以interrupt脫離線程阻塞狀態跳出程序體

HA主備怎麼預防腦裂

一般採用2個方法

  1. 仲裁
    當兩個節點出現分歧時,由第3方的仲裁者決定聽誰的。這個仲裁者,可能是一個鎖服務,一個共享盤或者其它什麼東西。
  2. fencing
    當不能確定某個節點的狀態時,通過fencing把對方幹掉,確保共享資源被完全釋放,前提是必須要有可靠的fence設備。

性別字段是否需要加索引

1.聚集索引,葉子節點存儲行記錄,InnoDB索引和記錄是存儲在一起的。
2.普通索引,葉子節點存儲了主鍵的值。
在InnoDB引擎中每個表都會有一個聚集索引,如果表定義了主鍵,那主鍵就是聚集索引.一個表只有一個聚集索引,其餘爲普通索引.如果性別sex字段定義爲普通的索引,那麼在使用普通索引查詢時,會先加載普通索引,通過普通索引查詢到實際行的主鍵,用主鍵通過聚集索引去查詢最終的行.
如果不對sex性別字段加索引,那麼查找過程就是直接全表掃描查詢到聚集索引定位到行,而不需要普通索引和聚集索引的切換,所以效率可能更高一點.
在這裏插入圖片描述

Https的SSL握手過程

Https協議由兩部分組成:http+ssl,即在http協議的基礎上增加了一層ssl的握手過程.

  • 瀏覽器作爲發起方,向網站發送一套瀏覽器自身支持的加密規則,比如客戶端支持的加密算法,Hash算法,ssl版本,以及一個28字節的隨機數client_random
  • .網站選出一套加密算法和hash算法,生成一個服務端隨機數server_random並以證書的形式返回給客戶端瀏覽器,這個證書還包含網站地址、公鑰public_key、證書的頒發機構CA以及證書過期時間。
  • .瀏覽器解析證書是否有效,如果無效則瀏覽器彈出提示框告警。如果證書有效,則根據server_random生成一個preMaster_secret和Master_secret[會話密鑰], master_secret 的生成需要 preMaster_key ,並需要 client_random 和 server_random 作爲種子。瀏覽器向服務器發送經過public_key加密的preMaster_secret,以及對握手消息取hash值並使用master_secret進行加密發送給網站.[客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的所有內容的hash值,用來供服務器校驗]
  • .服務器使用private_key 解密後得到preMaster_secret,再根據client_random 和 server_random 作爲種子得到master_secret.然後使用master_secret解密握手消息並計算hash值,跟瀏覽器發送的hash值對比是否一致.
    然後把握手消息通過master_secret進行對稱加密後返回給瀏覽器.以及把握手消息進行hash且master_secret加密後發給瀏覽器.[服務器握手結束通知,表示服務器的握手階段已經結束。這一項同時也是前面發送的所有內容的hash值,用來供客戶端校驗。]
  • .客戶端同樣可以使用master_secret進行解密得到握手消息.校驗握手消息的hash值是否跟服務器發送過來的hash值一致,一致則握手結束.通信開始
  • .以後的通信都是通過master_secret+對稱加密算法的方式進行. 客戶端與服務器進入加密通信,就完全是使用普通的HTTP協議,只不過用"會話密鑰"加密內容。SSL握手過程中如果有任何錯誤,都會使加密連接斷開,從而阻止了隱私信息的傳輸
    在這裏插入圖片描述
    非對稱加密算法:RSA,DSA/DSS
    對稱加密算法:AES,RC4,3DES
    HASH算法:MD5,SHA1,SHA256
    參考: http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html

select和epoll的區別

1 select有最大併發數限制,默認最大文件句柄數1024,可修改。
epoll沒有最大文件句柄數限制,僅受系統中進程能打開的最大文件句柄限制。
2 select效率低,每次都要線性掃描其維護的fd_set集合。
epoll只在集合不爲空才輪訓
3select存在內核空間和用戶空間的內存拷貝問題。
  epoll中減少內存拷貝,mmap將用戶空間的一塊地址和內核空間的一塊地址同時映射到相同的一塊物理內存地址

NIO使用的多路複用器是epoll

Epoll導致的selector空輪詢

  Java NIO Epoll 會導致 Selector 空輪詢,最終導致 CPU 100%
  官方聲稱在 JDK 1.6 版本的 update18 修復了該問題,但是直到 JDK 1.7 版本該問題仍舊存在,只不過該 BUG 發生概率降低了一些而已,它並沒有得到根本性解決
Netty的解決方案:
  對 Selector 的 select 操作週期進行統計,每完成一次空的 select 操作進行一次計數,若在某個週期內連續發生 N 次空輪詢,則判斷觸發了 Epoll 死循環 Bug。
  然後,Netty 重建 Selector 來解決。判斷是否是其他線程發起的重建請求,若不是則將原 SocketChannel 從舊的 Selector 上取消註冊,然後重新註冊到新的 Selector 上,最後將原來的 Selector 關閉。

正排索引和倒排索引

正排索引

也叫正向索引,正排表是以document文檔的ID爲關鍵字,記錄了document文檔中所有的關鍵字keyword的信息,所以在查找某個keyword的時候,會掃描正排表中每個document文檔,直到查出所有包含keyword的文檔。
圖示:
在這裏插入圖片描述

倒排索引

也叫反向索引,倒排表示以keyword關鍵字建立索引,關鍵詞keyword所對應的的表項記錄了出現這個keyword的所有文檔。表項包含了該文檔的ID和在該文檔中出現的位置情況。
倒排表一次可以查出keyword關鍵字對應的所有文檔,效率高於正排表。
在這裏插入圖片描述

正排索引是從文檔到關鍵字的映射(已知文檔求關鍵字)
倒排索引是從關鍵字到文檔的映射(已知關鍵字求文檔)

後記

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-1fe1ed04d7.css" rel="stylesheet">
                </div>
</article>
<div class="postTime">
            <div class="article-bar-bottom">
        <div class="reward-user-box">
            <span class="reward-word">有 <span class="num">0</span> 個人打賞</span>
                        </div>
    </div>
            <span class="time">
         </span>
</div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章