前言
前面我們講過Redis Cluster的搭建方式,也是本著應(yīng)用優(yōu)先的原則,所以對其基礎(chǔ)概念和原理幾乎沒有涉及,但當學(xué)會了Redis集群的搭建方式之后,對于其原來我們還是要知道一些的,所以這篇博客,我們將一起來學(xué)習(xí)Redis Cluster的一些相關(guān)知識。
導(dǎo)讀
在開始Redis Cluster的講解之前,還不熟悉Redis Cluster,還不知道怎么搭建Redis Cluster的小伙伴,可以先去看看以下這篇博客:
Java開發(fā) - 讓你少走彎路的Redis集群搭建
看完這篇博客,對于里面一些基礎(chǔ)知識,我們就開始給大家科普了。?
Redis Cluster
Redis Cluster是什么
我們首先要知道,Redis Cluster是在Redis3.0之后才出現(xiàn)的去中心化分片集群。傳統(tǒng)的Redis集群是基于主從復(fù)制加哨兵來實現(xiàn)的,這在前面的文章中博主也有詳細的搭建流程和原理剖析:
Java開發(fā) - 讓你少走彎路的Redis的主從復(fù)制
Java開發(fā) - 讓你少走彎路的Redis主從實現(xiàn)單節(jié)點哨兵模式
Java開發(fā) - 深入理解Redis哨兵機制原理
有需要的小伙伴自行前往查看。在這種傳統(tǒng)的Redis集群中,最多也只能有一個節(jié)點來提供寫服務(wù),這一點誰都無法改變。
不同于傳統(tǒng)的Redis集群模式,在Redis3.0后,Redis Cluster支持多主多從的方式,也就是可以同時開啟多個主節(jié)點,主節(jié)點之下再掛其他的從節(jié)點的方式。在這個過程中,Cluster會將數(shù)據(jù)分散到多個主節(jié)點上,這些主節(jié)點也都可以對外提供讀寫服務(wù)。這種方式突破了Redis單機存儲的內(nèi)存大小限制,擴展了集群的存儲容量。不僅如此,Redis Cluster的每個主節(jié)點都有至少一個從節(jié)點,當某個主節(jié)點掛掉后,Redis Cluster就通過故障轉(zhuǎn)移將其從節(jié)點切換為新的主節(jié)點。
總結(jié):Redis Cluster是一個去中心化的Redis集群,每個節(jié)點都會與其他節(jié)點保持互通,通過gossip協(xié)議來進行信息的交換、探測新加入的節(jié)點、監(jiān)聽縮容的節(jié)點。最大的好處是,Redis Cluster?需任何代理,客戶端會直接與集群中的節(jié)點連接。
注意:每個redis要放開兩個端口號,一個是6379,另外一個就是在這基礎(chǔ)上+10000,也就是16379,用來做節(jié)點間的通信?。?!
分片方式
在創(chuàng)建Redis Cluster集群時,需要保證至少6個Redis服務(wù),不要懷疑,就是6個,這6個Redis里的主節(jié)點會按照一定的規(guī)則來瓜分redis的16384個Slot槽,這個過程我們稱之為分片,也將是我們接下來要講解的內(nèi)容。
Slot槽是Redis Cluster的一個重要概念,它將哈希表拆分成多個小的哈希表,并將這些小的哈希表分布在不同的節(jié)點上。每個節(jié)點管理一個或多個Slot槽,每個Slot槽包含一定的數(shù)據(jù),這種分片的方式可以提高Redis的可擴展性和可靠性,避免單點故障時所有數(shù)據(jù)都丟失的問題。
哈希取模
哈希取模類似于我們使用HashMap選址的方式,我們對要存入的值的key進行hash計算,實際上是一個crc16效驗,根據(jù)這個最終的值來決定它應(yīng)該被分配在哪個Slot上,而這個Slot也決定了它在哪個節(jié)點上。
這里有個問題,在擴容或者縮容的時候,Slot槽可能需要重新進行分配,會導(dǎo)致key重新計算存儲位置,從?導(dǎo)致緩存失效,但我們也應(yīng)該知道,這種情況并不是總是經(jīng)常出現(xiàn)。
一致性哈希
一致性哈希將哈希值組成了一個閉合的虛擬圓環(huán),其大小在0 ~ 2^32-1之間,這個值非常熟悉有沒有?我們來看下圖:
這是一個擴容前的狀態(tài)圖,我們計算key的哈希值,確定它在環(huán)上的位置,然后順時針開始找,找到的第一個節(jié)點就是它這個key所在的節(jié)點,是不是很簡單?
但在我們需要向這個環(huán)中插入或者刪除節(jié)點時,就不需要重新對整個環(huán)/集群中的key進行重新運算,?致性哈希算法會將增減節(jié)點的影響限制在相鄰的節(jié)點上,而不對其他的節(jié)點造成影響。如下圖:
當我們node2和node4之間新增一個node5,此時只會把node4的一部分數(shù)據(jù)遷移到node5上‘如果對node4的服務(wù)進行下線,那么node4的數(shù)據(jù)將只遷移到相鄰的node3上,是不是很神奇?
一致性哈希算法在節(jié)點很多的時候還是不錯的,但在節(jié)點較少時,會因為刪除節(jié)點導(dǎo)致Slot槽或者說數(shù)據(jù)出現(xiàn)分布不均的情況,以上圖最開始4個節(jié)點的情況來說,如果刪除一個節(jié)點,勢必會有一個節(jié)點的數(shù)據(jù)由原來的四分之一(1/4)變成二分之一(1/2)。
以上是一個最差的結(jié)果,但在進行擴容和縮容的時候,Slot槽在重新分配時,怎么分配,這個規(guī)則掌握在我們的手中。比如說,人工分配容易導(dǎo)致食物,Slot就有一個自動平衡算法,具體做法就是通過redis-trib做rehash操作。但我還是要提醒大家,生產(chǎn)環(huán)境慎用?。?!
虛擬節(jié)點+?致性哈希
這有時候吧,節(jié)點在環(huán)上分配嚴重不均,也就是slot槽分配不均,節(jié)點又少,就有導(dǎo)致雪崩和數(shù)據(jù)傾斜,這時候就在一致性哈希的基礎(chǔ)上提出了一種新的虛擬節(jié)點的方式,如下圖:
注意:真實節(jié)點不放置到哈希環(huán)上,只有虛擬節(jié)點才會放上去??。?!
這種方式將通過實際節(jié)點搶占哈希環(huán)的方式變成了由實際節(jié)點下的虛擬節(jié)點來搶占的方式,簡單來說就是通過虛擬節(jié)點來映射實際的節(jié)點,好處是,?擴容或縮容時,其他節(jié)點只需要將自身虛擬節(jié)點下的一部分slot分配出去,從而達到slot槽的均勻分配,這個看起來就像是一種負載均衡的分配方式,而這正是我們所希望的。
選舉策略
在說之前,我想給大家推薦幾篇博客:
Redis 集群模式(Cluster)原理詳解
redis(六)Redis Cluster集群原理
Redis學(xué)習(xí)(二)之 Redis Cluster集群
大家的博客寫的各有千秋,也各有不足,所以需要綜合對照查看。下面,博主把自己對Redis Cluster的選舉的一些想法寫一下,希望對大家有幫助。
我們在上一篇Redis sentinel集群模式中說過,Redis之間通信采用的是gossip協(xié)議,該協(xié)議包含多種消息,包括ping、pong、meet、fail等等,他們都是干嘛的呢?我們先來一一了解下。
- ping:每個節(jié)點每秒都會給其他節(jié)點發(fā)送ping指令,包括自己的狀態(tài)和自己維護的集群的元數(shù)據(jù)信息;
- pong:pong是對對ping和meet消息的回復(fù),包含自己的狀態(tài)和其他信息,也用于信息廣播和更新;
- meet:一個節(jié)點發(fā)送meet指令給新加入的節(jié)點,倆節(jié)點一碰頭,新節(jié)點就加入集群,接著開始和其他節(jié)點通過ping指令進行通信;
- fail:從節(jié)點判斷自己的主節(jié)點fail之后,就廣播fail給其他節(jié)點,通知其他節(jié)點某個節(jié)點宕機,接著就開始進行選舉;
在通過fail廣播之后,其實并不會立刻開始選舉,這里存在一個網(wǎng)絡(luò)抖動的兼容策略。在配置文件中有這么一個參數(shù):cluster-node-timeout,超過這個時間后還是無法收到這個節(jié)點的ping信息,才會開始選舉策略。
在說明之前,我們要申明一點,只有主節(jié)點具備選舉的權(quán)利,從節(jié)點只負責(zé)主從復(fù)制,如果你配置了讀權(quán)限,那么從節(jié)點也將具備讀的權(quán)利,除此之外,從節(jié)點也只是可以廣播而已,不具備其他的權(quán)利了。(如果我說的不對,請大家糾正)我覺得這個東西可以通過我們前面集群搭建過程中測試的終端輸出得到結(jié)論,特地回去看了下,發(fā)現(xiàn)沒有截圖集群選舉的過程,但在sentinel集群中,我們是能看到sentinel選舉的過程的,只是在這里沒有參考的價值,回頭再搭集群的時候再截圖給大家看。
- 當master宕機后,最先發(fā)現(xiàn)其下線的一般是自己的slave,master狀態(tài)變?yōu)镕AIL;
- slave先給自己的epoch(即currentEpoch)增一,請求其它master給自己投票。這個消息通過slave廣播FAILOVER_AUTH_REQUEST包給集群中的每一個master;
- 這之后,slave會等待至少兩倍NODE_TIMEOUT時長接收投票結(jié)果,不管NODE_TIMEOUT何值,也至少會等待2秒,這是廣播去和對方收到之后回的市場,廣播每秒一次,所以是2s;
- master接收投票后給slave響應(yīng)FAILOVER_AUTH_ACK,并且在(NODE_TIMEOUT*2)時間內(nèi)不會給同一master的其它slave投票,因為master的slave可能不止一個,但同一時間,只能有一個slave發(fā)起選舉;
- 如果slave收到FAILOVER_AUTH_ACK響應(yīng)的epoch值小于自己的epoch,則會直接丟棄,否則,一旦slave收到多數(shù)master的FAILOVER_AUTH_ACK,則聲明自己贏得了選舉;
- 如果slave在兩倍的NODE_TIMEOUT時間內(nèi)(至少2秒)未贏得選舉,則放棄本次選舉,然后在四倍NODE_TIMEOUT時間(至少4秒)后重新發(fā)起選舉;
currentEpoch是集群狀態(tài)相關(guān)的一個參數(shù),可當作記錄集群狀態(tài)變更的遞增版本號。每個集群節(jié)點,都會通過 server.cluster->currentEpoch 記錄當前的 currentEpoch。集群節(jié)點創(chuàng)建時,不管是 master 還是 slave,currentEpoch 都是0,如果節(jié)點接收到來自其他節(jié)點的包時,發(fā)送者的 currentEpoch(消息頭部會包含發(fā)送者的 currentEpoch)大于當前節(jié)點的currentEpoch,那么當前節(jié)點會更新 currentEpoch 為發(fā)送者的 currentEpoch。由此,集群中所有節(jié)點的 currentEpoch 最終會達成一致,相當于對集群狀態(tài)的認知達成了一致,這也是集群存在的意義,即達到最終一致性。文章來源:http://www.zghlxwxcb.cn/news/detail-605730.html
結(jié)語
到這里,關(guān)于Redis Cluster的知識點就給大家介紹完畢了,關(guān)于Redis Cluster,你還知道哪些不為人知的秘密呢?歡迎評論區(qū)補充,大家一起來討論。不過話說回來,能用得起Redis Cluster的公司恐怕不多吧?光是這六個節(jié)點每年都要花不少錢呢,更何況還有其他的一些服務(wù)節(jié)點,只能說,用得起的公司是真的壕無人性啊!文章來源地址http://www.zghlxwxcb.cn/news/detail-605730.html
到了這里,關(guān)于Java開發(fā) - 深入理解Redis Cluster的工作原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!