原文出處:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-cluster.md
歡迎 star 關(guān)注 GitHub 項(xiàng)目最新動(dòng)態(tài)锦积!
面試題
redis 集群模式的工作原理能說(shuō)一下么芒帕?在集群模式下,redis 的 key 是如何尋址的丰介?分布式尋址都有哪些算法背蟆?了解一致性 hash 算法嗎?
面試官心理分析
在前幾年哮幢,redis 如果要搞幾個(gè)節(jié)點(diǎn)带膀,每個(gè)節(jié)點(diǎn)存儲(chǔ)一部分的數(shù)據(jù),得借助一些中間件來(lái)實(shí)現(xiàn)橙垢,比如說(shuō)有 codis
垛叨,或者 twemproxy
,都有柜某。有一些 redis 中間件嗽元,你讀寫(xiě) redis 中間件,redis 中間件負(fù)責(zé)將你的數(shù)據(jù)分布式存儲(chǔ)在多臺(tái)機(jī)器上的 redis 實(shí)例中喂击。
這兩年还棱,redis 不斷在發(fā)展,redis 也不斷有新的版本惭等,現(xiàn)在的 redis 集群模式,可以做到在多臺(tái)機(jī)器上办铡,部署多個(gè) redis 實(shí)例辞做,每個(gè)實(shí)例存儲(chǔ)一部分的數(shù)據(jù),同時(shí)每個(gè) redis 主實(shí)例可以?huà)?redis 從實(shí)例寡具,自動(dòng)確保說(shuō)秤茅,如果 redis 主實(shí)例掛了,會(huì)自動(dòng)切換到 redis 從實(shí)例上來(lái)童叠。
現(xiàn)在 redis 的新版本框喳,大家都是用 redis cluster 的,也就是 redis 原生支持的 redis 集群模式厦坛,那么面試官肯定會(huì)就 redis cluster 對(duì)你來(lái)個(gè)幾連炮五垮。要是你沒(méi)用過(guò) redis cluster,正常杜秸,以前很多人用 codis 之類(lèi)的客戶(hù)端來(lái)支持集群放仗,但是起碼你得研究一下 redis cluster 吧。
如果你的數(shù)據(jù)量很少撬碟,主要是承載高并發(fā)高性能的場(chǎng)景诞挨,比如你的緩存一般就幾個(gè) G莉撇,單機(jī)就足夠了,可以使用 replication惶傻,一個(gè) master 多個(gè) slaves棍郎,要幾個(gè) slave 跟你要求的讀吞吐量有關(guān),然后自己搭建一個(gè) sentinel 集群去保證 redis 主從架構(gòu)的高可用性银室。
redis cluster涂佃,主要是針對(duì)海量數(shù)據(jù)+高并發(fā)+高可用的場(chǎng)景。redis cluster 支撐 N 個(gè) redis master node粮揉,每個(gè) master node 都可以?huà)燧d多個(gè) slave node巡李。這樣整個(gè) redis 就可以橫向擴(kuò)容了。如果你要支撐更大數(shù)據(jù)量的緩存扶认,那就橫向擴(kuò)容更多的 master 節(jié)點(diǎn)侨拦,每個(gè) master 節(jié)點(diǎn)就能存放更多的數(shù)據(jù)了。
面試題剖析
redis cluster 介紹
- 自動(dòng)將數(shù)據(jù)進(jìn)行分片辐宾,每個(gè) master 上放一部分?jǐn)?shù)據(jù)
- 提供內(nèi)置的高可用支持狱从,部分 master 不可用時(shí),還是可以繼續(xù)工作的
在 redis cluster 架構(gòu)下叠纹,每個(gè) redis 要放開(kāi)兩個(gè)端口號(hào)季研,比如一個(gè)是 6379,另外一個(gè)就是 加1w 的端口號(hào)誉察,比如 16379与涡。
16379 端口號(hào)是用來(lái)進(jìn)行節(jié)點(diǎn)間通信的,也就是 cluster bus 的東西持偏,cluster bus 的通信驼卖,用來(lái)進(jìn)行故障檢測(cè)、配置更新鸿秆、故障轉(zhuǎn)移授權(quán)酌畜。cluster bus 用了另外一種二進(jìn)制的協(xié)議,gossip
協(xié)議卿叽,用于節(jié)點(diǎn)間進(jìn)行高效的數(shù)據(jù)交換桥胞,占用更少的網(wǎng)絡(luò)帶寬和處理時(shí)間。
節(jié)點(diǎn)間的內(nèi)部通信機(jī)制
基本通信原理
集群元數(shù)據(jù)的維護(hù)有兩種方式:集中式考婴、Gossip 協(xié)議贩虾。redis cluster 節(jié)點(diǎn)間采用 gossip 協(xié)議進(jìn)行通信。
集中式是將集群元數(shù)據(jù)(節(jié)點(diǎn)信息沥阱、故障等等)幾種存儲(chǔ)在某個(gè)節(jié)點(diǎn)上整胃。集中式元數(shù)據(jù)集中存儲(chǔ)的一個(gè)典型代表,就是大數(shù)據(jù)領(lǐng)域的 storm
。它是分布式的大數(shù)據(jù)實(shí)時(shí)計(jì)算引擎屁使,是集中式的元數(shù)據(jù)存儲(chǔ)的結(jié)構(gòu)在岂,底層基于 zookeeper(分布式協(xié)調(diào)的中間件)對(duì)所有元數(shù)據(jù)進(jìn)行存儲(chǔ)維護(hù)。
redis 維護(hù)集群元數(shù)據(jù)采用另一個(gè)方式蛮寂, gossip
協(xié)議蔽午,所有節(jié)點(diǎn)都持有一份元數(shù)據(jù),不同的節(jié)點(diǎn)如果出現(xiàn)了元數(shù)據(jù)的變更酬蹋,就不斷將元數(shù)據(jù)發(fā)送給其它的節(jié)點(diǎn)及老,讓其它節(jié)點(diǎn)也進(jìn)行元數(shù)據(jù)的變更。
集中式的好處在于范抓,元數(shù)據(jù)的讀取和更新骄恶,時(shí)效性非常好,一旦元數(shù)據(jù)出現(xiàn)了變更匕垫,就立即更新到集中式的存儲(chǔ)中僧鲁,其它節(jié)點(diǎn)讀取的時(shí)候就可以感知到;不好在于象泵,所有的元數(shù)據(jù)的更新壓力全部集中在一個(gè)地方寞秃,可能會(huì)導(dǎo)致元數(shù)據(jù)的存儲(chǔ)有壓力。
gossip 好處在于偶惠,元數(shù)據(jù)的更新比較分散春寿,不是集中在一個(gè)地方,更新請(qǐng)求會(huì)陸陸續(xù)續(xù)打到所有節(jié)點(diǎn)上去更新忽孽,降低了壓力绑改;不好在于,元數(shù)據(jù)的更新有延時(shí)兄一,可能導(dǎo)致集群中的一些操作會(huì)有一些滯后绢淀。
10000 端口:每個(gè)節(jié)點(diǎn)都有一個(gè)專(zhuān)門(mén)用于節(jié)點(diǎn)間通信的端口烧董,就是自己提供服務(wù)的端口號(hào)+10000,比如 7001瑟押,那么用于節(jié)點(diǎn)間通信的就是 17001 端口试溯。每個(gè)節(jié)點(diǎn)每隔一段時(shí)間都會(huì)往另外幾個(gè)節(jié)點(diǎn)發(fā)送
ping
消息,同時(shí)其它幾個(gè)節(jié)點(diǎn)接收到ping
之后返回pong
况脆。交換的信息:信息包括故障信息,節(jié)點(diǎn)的增加和刪除,hash slot 信息等等栖雾。
gossip 協(xié)議
gossip 協(xié)議包含多種消息,包含 ping
,pong
,meet
,fail
等等伟众。
- meet:某個(gè)節(jié)點(diǎn)發(fā)送 meet 給新加入的節(jié)點(diǎn)析藕,讓新節(jié)點(diǎn)加入集群中,然后新節(jié)點(diǎn)就會(huì)開(kāi)始與其它節(jié)點(diǎn)進(jìn)行通信凳厢。
redis-trib.rb add-node
其實(shí)內(nèi)部就是發(fā)送了一個(gè) gossip meet 消息給新加入的節(jié)點(diǎn)账胧,通知那個(gè)節(jié)點(diǎn)去加入我們的集群竞慢。
- ping:每個(gè)節(jié)點(diǎn)都會(huì)頻繁給其它節(jié)點(diǎn)發(fā)送 ping,其中包含自己的狀態(tài)還有自己維護(hù)的集群元數(shù)據(jù)治泥,互相通過(guò) ping 交換元數(shù)據(jù)筹煮。
- pong:返回 ping 和 meeet,包含自己的狀態(tài)和其它信息居夹,也用于信息廣播和更新败潦。
- fail:某個(gè)節(jié)點(diǎn)判斷另一個(gè)節(jié)點(diǎn) fail 之后,就發(fā)送 fail 給其它節(jié)點(diǎn)准脂,通知其它節(jié)點(diǎn)說(shuō)劫扒,某個(gè)節(jié)點(diǎn)宕機(jī)啦。
ping 消息深入
ping 時(shí)要攜帶一些元數(shù)據(jù)狸膏,如果很頻繁沟饥,可能會(huì)加重網(wǎng)絡(luò)負(fù)擔(dān)。
每個(gè)節(jié)點(diǎn)每秒會(huì)執(zhí)行 10 次 ping环戈,每次會(huì)選擇 5 個(gè)最久沒(méi)有通信的其它節(jié)點(diǎn)闷板。當(dāng)然如果發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)通信延時(shí)達(dá)到了 cluster_node_timeout / 2
,那么立即發(fā)送 ping院塞,避免數(shù)據(jù)交換延時(shí)過(guò)長(zhǎng)遮晚,落后的時(shí)間太長(zhǎng)了。比如說(shuō)拦止,兩個(gè)節(jié)點(diǎn)之間都 10 分鐘沒(méi)有交換數(shù)據(jù)了县遣,那么整個(gè)集群處于嚴(yán)重的元數(shù)據(jù)不一致的情況,就會(huì)有問(wèn)題汹族。所以 cluster_node_timeout
可以調(diào)節(jié)萧求,如果調(diào)得比較大,那么會(huì)降低 ping 的頻率顶瞒。
每次 ping夸政,會(huì)帶上自己節(jié)點(diǎn)的信息,還有就是帶上 1/10 其它節(jié)點(diǎn)的信息榴徐,發(fā)送出去守问,進(jìn)行交換。至少包含 3
個(gè)其它節(jié)點(diǎn)的信息坑资,最多包含 總節(jié)點(diǎn)數(shù)減 2
個(gè)其它節(jié)點(diǎn)的信息耗帕。
分布式尋址算法
- hash 算法(大量緩存重建)
- 一致性 hash 算法(自動(dòng)緩存遷移)+ 虛擬節(jié)點(diǎn)(自動(dòng)負(fù)載均衡)
- redis cluster 的 hash slot 算法
hash 算法
來(lái)了一個(gè) key,首先計(jì)算 hash 值袱贮,然后對(duì)節(jié)點(diǎn)數(shù)取模仿便。然后打在不同的 master 節(jié)點(diǎn)上。一旦某一個(gè) master 節(jié)點(diǎn)宕機(jī),所有請(qǐng)求過(guò)來(lái)嗽仪,都會(huì)基于最新的剩余 master 節(jié)點(diǎn)數(shù)去取模荒勇,嘗試去取數(shù)據(jù)。這會(huì)導(dǎo)致大部分的請(qǐng)求過(guò)來(lái)钦幔,全部無(wú)法拿到有效的緩存枕屉,導(dǎo)致大量的流量涌入數(shù)據(jù)庫(kù)。
一致性 hash 算法
一致性 hash 算法將整個(gè) hash 值空間組織成一個(gè)虛擬的圓環(huán)鲤氢,整個(gè)空間按順時(shí)針?lè)较蚪M織搀擂,下一步將各個(gè) master 節(jié)點(diǎn)(使用服務(wù)器的 ip 或主機(jī)名)進(jìn)行 hash。這樣就能確定每個(gè)節(jié)點(diǎn)在其哈希環(huán)上的位置卷玉。
來(lái)了一個(gè) key哨颂,首先計(jì)算 hash 值,并確定此數(shù)據(jù)在環(huán)上的位置相种,從此位置沿環(huán)順時(shí)針“行走”威恼,遇到的第一個(gè) master 節(jié)點(diǎn)就是 key 所在位置。
在一致性哈希算法中寝并,如果一個(gè)節(jié)點(diǎn)掛了箫措,受影響的數(shù)據(jù)僅僅是此節(jié)點(diǎn)到環(huán)空間前一個(gè)節(jié)點(diǎn)(沿著逆時(shí)針?lè)较蛐凶哂龅降牡谝粋€(gè)節(jié)點(diǎn))之間的數(shù)據(jù),其它不受影響衬潦。增加一個(gè)節(jié)點(diǎn)也同理斤蔓。
燃鵝,一致性哈希算法在節(jié)點(diǎn)太少時(shí)镀岛,容易因?yàn)楣?jié)點(diǎn)分布不均勻而造成緩存熱點(diǎn)的問(wèn)題弦牡。為了解決這種熱點(diǎn)問(wèn)題,一致性 hash 算法引入了虛擬節(jié)點(diǎn)機(jī)制漂羊,即對(duì)每一個(gè)節(jié)點(diǎn)計(jì)算多個(gè) hash驾锰,每個(gè)計(jì)算結(jié)果位置都放置一個(gè)虛擬節(jié)點(diǎn)。這樣就實(shí)現(xiàn)了數(shù)據(jù)的均勻分布走越,負(fù)載均衡椭豫。
redis cluster 的 hash slot 算法
redis cluster 有固定的 16384
個(gè) hash slot,對(duì)每個(gè) key
計(jì)算 CRC16
值旨指,然后對(duì) 16384
取模赏酥,可以獲取 key 對(duì)應(yīng)的 hash slot。
redis cluster 中每個(gè) master 都會(huì)持有部分 slot淤毛,比如有 3 個(gè) master,那么可能每個(gè) master 持有 5000 多個(gè) hash slot算柳。hash slot 讓 node 的增加和移除很簡(jiǎn)單低淡,增加一個(gè) master,就將其他 master 的 hash slot 移動(dòng)部分過(guò)去,減少一個(gè) master蔗蹋,就將它的 hash slot 移動(dòng)到其他 master 上去何荚。移動(dòng) hash slot 的成本是非常低的≈砗迹客戶(hù)端的 api餐塘,可以對(duì)指定的數(shù)據(jù),讓他們走同一個(gè) hash slot皂吮,通過(guò) hash tag
來(lái)實(shí)現(xiàn)戒傻。
任何一臺(tái)機(jī)器宕機(jī),另外兩個(gè)節(jié)點(diǎn)蜂筹,不影響的需纳。因?yàn)?key 找的是 hash slot,不是機(jī)器艺挪。
redis cluster 的高可用與主備切換原理
redis cluster 的高可用的原理不翩,幾乎跟哨兵是類(lèi)似的。
判斷節(jié)點(diǎn)宕機(jī)
如果一個(gè)節(jié)點(diǎn)認(rèn)為另外一個(gè)節(jié)點(diǎn)宕機(jī)麻裳,那么就是 pfail
口蝠,主觀宕機(jī)。如果多個(gè)節(jié)點(diǎn)都認(rèn)為另外一個(gè)節(jié)點(diǎn)宕機(jī)了津坑,那么就是 fail
妙蔗,客觀宕機(jī),跟哨兵的原理幾乎一樣国瓮,sdown灭必,odown。
在 cluster-node-timeout
內(nèi)乃摹,某個(gè)節(jié)點(diǎn)一直沒(méi)有返回 pong
禁漓,那么就被認(rèn)為 pfail
。
如果一個(gè)節(jié)點(diǎn)認(rèn)為某個(gè)節(jié)點(diǎn) pfail
了孵睬,那么會(huì)在 gossip ping
消息中播歼,ping
給其他節(jié)點(diǎn),如果超過(guò)半數(shù)的節(jié)點(diǎn)都認(rèn)為 pfail
了掰读,那么就會(huì)變成 fail
秘狞。
從節(jié)點(diǎn)過(guò)濾
對(duì)宕機(jī)的 master node,從其所有的 slave node 中蹈集,選擇一個(gè)切換成 master node烁试。
檢查每個(gè) slave node 與 master node 斷開(kāi)連接的時(shí)間,如果超過(guò)了 cluster-node-timeout * cluster-slave-validity-factor
拢肆,那么就沒(méi)有資格切換成 master
减响。
從節(jié)點(diǎn)選舉
每個(gè)從節(jié)點(diǎn)靖诗,都根據(jù)自己對(duì) master 復(fù)制數(shù)據(jù)的 offset,來(lái)設(shè)置一個(gè)選舉時(shí)間支示,offset 越大(復(fù)制數(shù)據(jù)越多)的從節(jié)點(diǎn)刊橘,選舉時(shí)間越靠前,優(yōu)先進(jìn)行選舉颂鸿。
所有的 master node 開(kāi)始 slave 選舉投票促绵,給要進(jìn)行選舉的 slave 進(jìn)行投票,如果大部分 master node(N/2 + 1)
都投票給了某個(gè)從節(jié)點(diǎn)嘴纺,那么選舉通過(guò)败晴,那個(gè)從節(jié)點(diǎn)可以切換成 master。
從節(jié)點(diǎn)執(zhí)行主備切換颖医,從節(jié)點(diǎn)切換為主節(jié)點(diǎn)位衩。
與哨兵比較
整個(gè)流程跟哨兵相比,非常類(lèi)似熔萧,所以說(shuō)糖驴,redis cluster 功能強(qiáng)大,直接集成了 replication 和 sentinel 的功能佛致。