面試題
redis 集群模式的工作原理能說一下么胳喷?在集群模式下湃番,redis 的 key 是如何尋址的?分布式尋址都有哪些算法吭露?了解一致性 hash 算法嗎吠撮?
面試官心理分析
在前幾年,redis 如果要搞幾個(gè)節(jié)點(diǎn)讲竿,每個(gè)節(jié)點(diǎn)存儲(chǔ)一部分的數(shù)據(jù)泥兰,得借助一些中間件來實(shí)現(xiàn)弄屡,比如說有 codis
,或者 twemproxy
鞋诗,都有膀捷。有一些 redis 中間件,你讀寫 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í)例可以掛 redis 從實(shí)例安券,自動(dòng)確保說,如果 redis 主實(shí)例掛了氓英,會(huì)自動(dòng)切換到 redis 從實(shí)例頂上來侯勉。
現(xiàn)在 redis 的新版本,大家都是用 redis cluster 的铝阐,也就是 redis 原生支持的 redis 集群模式址貌,那么面試官肯定會(huì)就 redis cluster 對(duì)你來個(gè)幾連炮。要是你沒用過 redis cluster徘键,正常练对,以前很多人用 codis 之類的客戶端來支持集群,但是起碼你得研究一下 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 都可以掛載多個(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 要放開兩個(gè)端口號(hào),比如一個(gè)是 6379逝嚎,另外一個(gè)就是 加1w 的端口號(hào)扁瓢,比如 16379。
16379 端口號(hào)是用來進(jìn)行節(jié)點(diǎn)間通信的补君,也就是 cluster bus 的東西引几,cluster bus 的通信,用來進(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ī)制
基本通信原理
- 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è)專門用于節(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ì)開始與其它節(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ù)洛退,互相通過 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)說,某個(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è)最久沒有通信的其它節(jié)點(diǎn)奠货。當(dāng)然如果發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)通信延時(shí)達(dá)到了 cluster_node_timeout / 2
,那么立即發(fā)送 ping粘优,避免數(shù)據(jù)交換延時(shí)過長(zhǎng)仇味,落后的時(shí)間太長(zhǎng)了。比如說雹顺,兩個(gè)節(jié)點(diǎn)之間都 10 分鐘沒有交換數(shù)據(jù)了丹墨,那么整個(gè)集群處于嚴(yán)重的元數(shù)據(jù)不一致的情況,就會(huì)有問題嬉愧。所以 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)-2
個(gè)其它節(jié)點(diǎn)的信息挂疆。
分布式尋址算法
- hash 算法(大量緩存重建)
- 一致性 hash 算法(自動(dòng)緩存遷移)+ 虛擬節(jié)點(diǎn)(自動(dòng)負(fù)載均衡)
- redis cluster 的 hash slot 算法
hash 算法
來了一個(gè) key,首先計(jì)算 hash 值下翎,然后對(duì)節(jié)點(diǎn)數(shù)取模缤言。然后打在不同的 master 節(jié)點(diǎn)上。一旦某一個(gè) master 節(jié)點(diǎn)宕機(jī)视事,所有請(qǐng)求過來胆萧,都會(huì)基于最新的剩余 master 節(jié)點(diǎn)數(shù)去取模,嘗試去取數(shù)據(jù)俐东。這會(huì)導(dǎo)致大部分的請(qǐng)求過來跌穗,全部無法拿到有效的緩存,導(dǎo)致大量的流量涌入數(shù)據(jù)庫虏辫。
一致性 hash 算法
一致性 hash 算法將整個(gè) hash 值空間組織成一個(gè)虛擬的圓環(huán)瞻离,整個(gè)空間按順時(shí)針方向組織,下一步將各個(gè) master 節(jié)點(diǎn)(使用服務(wù)器的 ip 或主機(jī)名)進(jìn)行 hash乒裆。這樣就能確定每個(gè)節(jié)點(diǎn)在其哈希環(huán)上的位置套利。
來了一個(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í)針方向行走遇到的第一個(gè)節(jié)點(diǎn))之間的數(shù)據(jù),其它不受影響族购。增加一個(gè)節(jié)點(diǎn)也同理壳贪。
燃鵝,一致性哈希算法在節(jié)點(diǎn)太少時(shí)寝杖,容易因?yàn)楣?jié)點(diǎn)分布不均勻而造成緩存熱點(diǎn)的問題违施。為了解決這種熱點(diǎ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)部分過去扯键,減少一個(gè) master睦袖,就將它的 hash slot 移動(dòng)到其他 master 上去。移動(dòng) hash slot 的成本是非常低的荣刑∠隗希客戶端的 api,可以對(duì)指定的數(shù)據(jù)厉亏,讓他們走同一個(gè) hash slot董习,通過 hash tag
來實(shí)現(xiàn)。
任何一臺(tái)機(jī)器宕機(jī)爱只,另外兩個(gè)節(jié)點(diǎn)皿淋,不影響的。因?yàn)?key 找的是 hash slot,不是機(jī)器窝趣。
redis cluster 的高可用與主備切換原理
redis cluster 的高可用的原理疯暑,幾乎跟哨兵是類似的
判斷節(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)一直沒有返回 pong
吏祸,那么就被認(rèn)為 pfail
对蒲。
如果一個(gè)節(jié)點(diǎn)認(rèn)為某個(gè)節(jié)點(diǎn) pfail
了,那么會(huì)在 gossip ping
消息中贡翘,ping
給其他節(jié)點(diǎn)蹈矮,如果超過半數(shù)的節(jié)點(diǎn)都認(rèn)為 pfail
了,那么就會(huì)變成 fail
鸣驱。
從節(jié)點(diǎn)過濾
對(duì)宕機(jī)的 master node泛鸟,從其所有的 slave node 中,選擇一個(gè)切換成 master node踊东。
檢查每個(gè) slave node 與 master node 斷開連接的時(shí)間北滥,如果超過了 cluster-node-timeout * cluster-slave-validity-factor
,那么就沒有資格切換成 master
闸翅。
從節(jié)點(diǎn)選舉
每個(gè)從節(jié)點(diǎn)再芋,都根據(jù)自己對(duì) master 復(fù)制數(shù)據(jù)的 offset,來設(shè)置一個(gè)選舉時(shí)間坚冀,offset 越大(復(fù)制數(shù)據(jù)越多)的從節(jié)點(diǎn)济赎,選舉時(shí)間越靠前,優(yōu)先進(jìn)行選舉记某。
所有的 master node 開始 slave 選舉投票司训,給要進(jìn)行選舉的 slave 進(jìn)行投票,如果大部分 master node(N/2 + 1)
都投票給了某個(gè)從節(jié)點(diǎn)液南,那么選舉通過壳猜,那個(gè)從節(jié)點(diǎn)可以切換成 master。
從節(jié)點(diǎn)執(zhí)行主備切換滑凉,從節(jié)點(diǎn)切換為主節(jié)點(diǎn)统扳。
與哨兵比較
整個(gè)流程跟哨兵相比喘帚,非常類似,所以說咒钟,redis cluster 功能強(qiáng)大啥辨,直接集成了 replication 和 sentinel 的功能。