本文轉載自微信公眾號,孤獨煙
本文故事絕對真實,如有雷同,絕對不是巧合!
話說前幾天有一次,某大廠的二面。然后呢,煙哥那天剛好有事,所以去不了。于是就約了一場視頻面試了!
于是呢,煙哥提前十分鐘在公司里頭找了一個廁所的坑位,然后進去隨手一鎖門….(以下省略10000字)…
唉…
我竟然…
我竟然…
我竟然又帶薪上廁所了,而且上了一小時!我有罪!
額,是這樣的,大廠的廁所是有雅間的。所以環境還馬馬虎虎,鼻子還是正常的!
OK,交待完背景,然后開始我們的主題!
全局Session
當時的情形是這樣的,先介紹一下自己的項目。然后介紹完項目背景以后,因為有一個登陸模塊。于是乎有了如下問題
面試官:“先說說全局Session干嘛用的,你們那邊全局session是怎么做的?”
這個問題還是很容易的。因為一個應用通常有多臺服務器,在登陸成功后,Session只會在其中某一臺存儲。需要想辦法讓多臺服務器都識別到這個Session,因此才有了這個全局Session的概念。我們用的是后端統一存儲的策略,有專門的用戶管理系統,上面存儲著用戶信息以及Session狀態。
煙哥注:目前業內在解決全局Sesssion上無外乎四種方法
- (1)服務端自己進行同步,例如早期的項目,大概是07年那會的(我司老古董項目啊),那會Tomcat的集群能力不行。用的是Weblogic服務器,使用的就是Weblogic的Session復制功能。
- (2)客戶端存儲法,將session存儲到瀏覽器cookie中,每次http請求都帶session。這里摸著良心坦白說,該方案從沒用過,安全性太差。
- (3)反向代理hash一致性,不需要修改應用代碼。修改Nginx的配置,保證同一個ip的請求落在同一個web-server上即可。
- (4)后端統一存儲,后端統一找一個中間件將Session存起來即可,這個中間件是數據庫或者緩存。
面試官:“那你知道這個平臺里Session怎么管理的么?”
必須不知道啊!對我們來說該平臺只是一個黑盒,會調接口即可。
于是乎,一個讓我頭疼的問題出現了!
面試官:“如果讓你設計這樣一個平臺,管理這些Session,你會怎么設計?”
用redis來存儲Session,用sessionId作為key,用session當value進行存儲。
OK,這時我頭腦浮現的架構是這樣的
面試官:"如果redis掛了呢?"
咦,這個時候,我突然懵了。面試官到底想問我什么?難道掛了,不是redis從服務器頂上么?這個問題莫非有什么玄機?
然后我是這樣答的。
一般情況,主redis掛了,由從redis頂上。如果redis某個slot的主從節點全掛了,
那么我們在rediscluster中有一個配置叫
cluster-require-full-coverage
當cluster-require-full-coverage為no時,表示當負責一個插槽的主庫下線且沒有相應的從庫進行故障恢復時,集群仍然可用。但是該槽的相關命令不可用。
當cluster-require-full-coverage為yes時,表示當負責一個插槽的主庫下線且沒有相應的從庫進行故障恢復時,集群不可用。
該值默認值為yes,也就是集群處于不可用的狀態。
這個時候,可能出現了網絡中斷!
面試官:"你的意思是,redis掛了,整個集群數據就不可用了?"
我回答嗯嗯,是的!
這個時候,面試官
面試官:"你不知道一致性哈希算法么?回去了解一下!"
然后我突然懵了。原來是我想太多,他這樣問完,我才get到他問的點。
煙哥注:所以我才說這個面試我有點失敗,和面試官不在一個頻道上。如果是現場面,可以現場畫圖,則不會出現這種問題!
面試官想到的架構應該是這樣的
上圖中,由于有4臺服務器(排除從庫),因此公式為hash(sessionId) % 4 = 2 ,可知定位到了第2號服務器。
但是呢,普通的如果4臺緩存服務器已經不能滿足我們的緩存需求,那么我們應該怎么做呢?很簡單,多增加幾臺緩存服務器不就行了!
假設:我們增加了一臺緩存服務器,那么緩存服務器的數量就由4臺變成了5臺。那么原本hash(sessionId) % 4 = 2 的公式就變成了hash(sessionId) % 5 = ?, 可想而知這個結果肯定不是2的,這種情況帶來的結果就是當服務器數量變動時,所有緩存的位置都要發生改變!
于是乎,他才想引我去答一致性哈希算法!總之,該死的破網絡!導致兩邊不在一個頻道上!
一致性哈希
既然都提到了一致性哈希算法了,就當復習一下吧~~
一致性哈希算法的精髓只有一個:對2^32次方取模。
我們將二的三十二次方想象成一個圓,這個圓上的數字就是即0~(2^32)-1。
如下圖所示
這時候有三臺緩存服務器A、B、C。
我們
hash(服務器A的IP地址) % 2^32
插播一下,寫到這里,這里我又想起一道題了!
有哪些常見的hash算法啊?
OK,先繼續我們的話題。經過上面的運算,我們算出的結果一定是一個0到2^32-1之間的一個整數,我們就用算出的這個整數,代表服務器A,既然這個整數肯定處于0到2^32-1之間,那么,上圖中的hash環上必定有一個點與這個整數對應,我們使用這個整數代表服務器A,那么,服務器A就可以映射到這個環上。
同理進行
hash(服務器B的IP地址) % 2^32
hash(服務器C的IP地址) % 2^32
于是,得到了下面這一張圖
那么,我們要用服務器存儲session,那么我們用sessionId做key,進行如下運算
hash(sessionId) % 2^32
得到的一個環上的值。那我們怎么知道session被存到哪個服務器上呢,OK,順時針方向找到的第一個服務器就是。如下圖所示
假設,我們現在有四個session,分別進行映射運算后得到如下的環
這么做的好處?
使用一致性算法后,當服務器B移除的時候,服務器B上的數據會順時針移動到服務器C上去。從而避免了當服務器數量發生改變當時候,所有的session都失效。
如下所示
虛擬槽的應用?
真實世界中,服務器可能映射的并不均勻。這就導致了數據可能是下面這樣的,大量的數據在A服務器上,導致數據不均勻
為了解決這個問題,我們給A、B、C三臺服務器引入虛擬節點。如下圖所示(圖中黃色節點為虛擬節點)
如圖所示,2號session和3號session映射到了虛擬B節點,就會存儲到真實的B節點上。通過引入虛擬節點的方式,實現數據的均勻分配!
最后,本文內容全當復習一次一致性哈希算法。希望大家有所收獲。