一文講清RedisCluster
1 集群的意義
從單機(jī)的一主多從復(fù)制架構(gòu)到現(xiàn)在的分布式架構(gòu)
主要有如下維度:
- 業(yè)務(wù)
- 追求更高QPS
- 數(shù)據(jù)量
- Scale Up已經(jīng)無法滿足,超過了單機(jī)極限,考慮Scale Out分布式
- 網(wǎng)絡(luò)流量
- 業(yè)務(wù)流量超過服務(wù)器網(wǎng)卡上限,考慮分布式分流
- 離線計(jì)算
- 需要中間環(huán)節(jié)緩沖等需求
2 meet
節(jié)點(diǎn)之間完成相互通信的基礎(chǔ),有一定的頻率和規(guī)則。
CLUSTER MEET命令被用來連接不同的開啟集群支持的 Redis 節(jié)點(diǎn),以進(jìn)入工作集群。
2.1 基本思想
每個(gè)節(jié)點(diǎn)默認(rèn)都是相互不信任的,并且被認(rèn)為是未知的節(jié)點(diǎn),以便萬一因?yàn)橄到y(tǒng)管理錯(cuò)誤或地址被修改,而不太可能將多個(gè)不同的集群節(jié)點(diǎn)混成一個(gè)集群。
因此,為了使給定節(jié)點(diǎn)能將另一個(gè)節(jié)點(diǎn)接收到組成 Redis Cluster 的節(jié)點(diǎn)列表中,這里只有兩種方法:
- 系統(tǒng)管理員發(fā)送一個(gè)CLUSTER MEET命令強(qiáng)制一個(gè)節(jié)點(diǎn)會(huì)見另一個(gè)節(jié)點(diǎn)
- 一個(gè)已知節(jié)點(diǎn)發(fā)送一個(gè)保存在 gossip 部分的節(jié)點(diǎn)列表,包含著未知節(jié)點(diǎn)。如果接收的節(jié)點(diǎn)已經(jīng)將發(fā)送節(jié)點(diǎn)信任為已知節(jié)點(diǎn),它會(huì)處理 gossip 部分并且發(fā)送一個(gè)握手消息給未知的節(jié)點(diǎn)。
Redis Cluster 需要形成一個(gè)完整的網(wǎng)絡(luò)(每個(gè)節(jié)點(diǎn)都連接著其他每個(gè)節(jié)點(diǎn)),但為創(chuàng)建一個(gè)集群,不需要發(fā)送形成網(wǎng)絡(luò)所需的所有CLUSTER MEET命令。發(fā)送CLUSTER MEET消息以便每個(gè)節(jié)點(diǎn)能夠到達(dá)其他每個(gè)節(jié)點(diǎn)只需通過一條已知的節(jié)點(diǎn)鏈就夠了。由于在心跳包中會(huì)交換 gossip 信息,將會(huì)創(chuàng)建節(jié)點(diǎn)間缺失的鏈接。
所以,如果我們通過CLUSTER MEET鏈接節(jié)點(diǎn) A 和 B ,并且 B 和 C 有鏈接,那么節(jié)點(diǎn) A 和 C 會(huì)發(fā)現(xiàn)他們握手和創(chuàng)建鏈接的方法。
2.2 案例
假設(shè)某一集群有A、B、C、D四個(gè)節(jié)點(diǎn),可以只發(fā)送以下一組命令給 A :
- CLUSTER MEET B-ip B-port
- CLUSTER MEET C-ip C-port
- CLUSTER MEET D-ip D-port
由于 A 知道及被其他所有節(jié)點(diǎn)知道,它將會(huì)在發(fā)送的心跳包中包含gossip部分,這將允許其他每個(gè)節(jié)點(diǎn)彼此都創(chuàng)建一個(gè)鏈接,即使集群很大,也能在數(shù)秒內(nèi)形成一個(gè)完整網(wǎng)絡(luò)。
CLUSTER MEET無需相互執(zhí)行,即若發(fā)送命令給 A 以加入B ,那就不必也發(fā)送給 B 以加入 A。
2.3 實(shí)現(xiàn)細(xì)節(jié):MEET 和 PING 包
當(dāng)某一給定節(jié)點(diǎn)接收到一個(gè)MEET消息時(shí),命令中指定的節(jié)點(diǎn)仍不知發(fā)送了該命令,所以為使節(jié)點(diǎn)強(qiáng)制將接收命令的節(jié)點(diǎn)將它作為信任的節(jié)點(diǎn)接受它,它會(huì)發(fā)送MEET包而非PING包。兩個(gè)消息包有相同的格式,但是MEET強(qiáng)制使接收消息包的節(jié)點(diǎn)確認(rèn)發(fā)送消息包的節(jié)點(diǎn)為可信任的。
3 指派槽
- 把16384個(gè)槽平分給節(jié)點(diǎn)管理,每個(gè)節(jié)點(diǎn)只對(duì)自己負(fù)責(zé)的槽進(jìn)行讀寫
- 每個(gè)節(jié)點(diǎn)間都相互通信,所以每個(gè)節(jié)點(diǎn)都知道其它節(jié)點(diǎn)所管理槽的范圍
客戶端與指派槽
4 集群伸縮
集群的伸縮包括新節(jié)點(diǎn)的加入和舊節(jié)點(diǎn)退出。
4.1 加入新節(jié)點(diǎn)
Redis集群加入新節(jié)點(diǎn)主要如下幾步:
- 準(zhǔn)備新節(jié)點(diǎn)
啟動(dòng)一個(gè)集群模式下的Redis節(jié)點(diǎn)
- 加入集群
通過與任意一集群中的節(jié)點(diǎn)握手加入新節(jié)點(diǎn)
- 遷移slot到新節(jié)點(diǎn)
再向新節(jié)點(diǎn)分配它負(fù)責(zé)的slot并向其遷移slot對(duì)應(yīng)數(shù)據(jù)。
由于Redis采用Gossip協(xié)議,所以可讓新節(jié)點(diǎn)與任一現(xiàn)有集群節(jié)點(diǎn)握手,一段時(shí)間后整個(gè)集群都會(huì)知道加入了新節(jié)點(diǎn)。
4.1.1 案例
向如下集群中新加入一個(gè)節(jié)點(diǎn)6385。由于負(fù)載均衡的要求,加入后四個(gè)節(jié)點(diǎn)每個(gè)節(jié)點(diǎn)負(fù)責(zé)4096個(gè)slots,但集群中原來的每個(gè)節(jié)點(diǎn)都負(fù)責(zé)5462個(gè)slots,所以6379、6380、6381節(jié)點(diǎn)都需要向新的節(jié)點(diǎn)6385遷移1366個(gè)slots。
Redis集群并沒有一個(gè)自動(dòng)實(shí)現(xiàn)負(fù)載均衡的工具,把多少slots從哪個(gè)節(jié)點(diǎn)遷移到哪個(gè)節(jié)點(diǎn)完全是由用戶指定。
遷移數(shù)據(jù)的流程圖
遷移key可以用pipeline進(jìn)行批量的遷移。
對(duì)于擴(kuò)容,原理已經(jīng)很清晰了,至于具體操作,網(wǎng)上很多。
至于縮容,也是先手動(dòng)完成數(shù)據(jù)遷移,再關(guān)閉redis。收縮時(shí)如果下線的節(jié)點(diǎn)有負(fù)責(zé)的槽需要遷移到其他節(jié)點(diǎn),再通過cluster forget命令讓集群內(nèi)所有節(jié)點(diǎn)忘記被下線節(jié)點(diǎn)
5 客戶端路由
5.1 moved重定向
每個(gè)節(jié)點(diǎn)通信共享Redis Cluster中槽和集群中對(duì)應(yīng)節(jié)點(diǎn)的關(guān)系。
- 客戶端向Redis Cluster的任一節(jié)點(diǎn)發(fā)送命令
- 接收命令的節(jié)點(diǎn)再計(jì)算自己的槽和對(duì)應(yīng)節(jié)點(diǎn)
1.如果保存數(shù)據(jù)的槽被分配給當(dāng)前節(jié)點(diǎn),則去槽中執(zhí)行命令,并把命令執(zhí)行結(jié)果返回給客戶端
2.如果保存數(shù)據(jù)的槽不在當(dāng)前節(jié)點(diǎn)的管理范圍內(nèi),則向客戶端返回moved重定向異常
3.客戶端接收到節(jié)點(diǎn)返回的結(jié)果,如果是moved異常,則從moved異常中獲取目標(biāo)節(jié)點(diǎn)的信息
4.客戶端向目標(biāo)節(jié)點(diǎn)發(fā)送命令,獲取命令執(zhí)行結(jié)果
客戶端不會(huì)自動(dòng)找到目標(biāo)節(jié)點(diǎn)執(zhí)行命令,需要二次執(zhí)行
5.2 ask重定向
由于集群伸縮時(shí),需要數(shù)據(jù)遷移。
當(dāng)客戶端訪問某key,節(jié)點(diǎn)告訴客戶端key在源節(jié)點(diǎn),再去源節(jié)點(diǎn)訪問時(shí),卻發(fā)現(xiàn)key已遷移到目標(biāo)節(jié)點(diǎn),就會(huì)返回ask。
- 客戶端向目標(biāo)節(jié)點(diǎn)發(fā)送命令,目標(biāo)節(jié)點(diǎn)中的槽已經(jīng)遷移到其它節(jié)點(diǎn)
- 目標(biāo)節(jié)點(diǎn)會(huì)返回ask轉(zhuǎn)向給客戶端
- 客戶端向新節(jié)點(diǎn)發(fā)送Asking命令
- 再向新節(jié)點(diǎn)發(fā)送命令
- 新節(jié)點(diǎn)執(zhí)行命令,把命令執(zhí)行結(jié)果返回給客戶端
為什么不能簡(jiǎn)單使用MOVED重定向?
因?yàn)殡m然MOVED意味著我們認(rèn)為哈希槽由另一個(gè)節(jié)點(diǎn)永久提供,并且應(yīng)該對(duì)指定節(jié)點(diǎn)嘗試下一個(gè)查詢,所以ASK意味著僅將下一個(gè)查詢發(fā)送到指定節(jié)點(diǎn)。
之所以需要這樣做,是因?yàn)橄乱粋€(gè)關(guān)于哈希槽的查詢可能是關(guān)于仍在A中的鍵的,因此我們始終希望客戶端嘗試A,然后在需要時(shí)嘗試B。由于只有16384個(gè)可用的哈希槽中有一個(gè)發(fā)生,因此群集上的性能下降是可以接受的。
5.3 moved V.S ask
都是客戶端重定向
- moved:槽已經(jīng)確定轉(zhuǎn)移
- ask:槽還在遷移中
5.4 smart智能客戶端
目標(biāo)
追求性能
設(shè)計(jì)思路
- 從集群中選一個(gè)可運(yùn)行節(jié)點(diǎn),使用Cluster slots初始化槽和節(jié)點(diǎn)映射
- 將Cluster slots的結(jié)果映射在本地,為每個(gè)節(jié)點(diǎn)創(chuàng)建JedisPool,然后就可以進(jìn)行數(shù)據(jù)讀寫操作
注意事項(xiàng)
- 每個(gè)JedisPool中緩存了slot和節(jié)點(diǎn)node的關(guān)系
- key和slot的關(guān)系:對(duì)key進(jìn)行CRC16規(guī)則進(jìn)行hash后與16383取余得到的結(jié)果就是槽
- JedisCluster啟動(dòng)時(shí),已經(jīng)知道key,slot和node之間的關(guān)系,可以找到目標(biāo)節(jié)點(diǎn)
- JedisCluster對(duì)目標(biāo)節(jié)點(diǎn)發(fā)送命令,目標(biāo)節(jié)點(diǎn)直接響應(yīng)給JedisCluster
- 如果JedisCluster與目標(biāo)節(jié)點(diǎn)連接出錯(cuò),則JedisCluster會(huì)知道連接的節(jié)點(diǎn)是一個(gè)錯(cuò)誤的節(jié)點(diǎn)
- 此時(shí)JedisCluster會(huì)隨機(jī)節(jié)點(diǎn)發(fā)送命令,隨機(jī)節(jié)點(diǎn)返回moved異常給JedisCluster
- JedisCluster會(huì)重新初始化slot與node節(jié)點(diǎn)的緩存關(guān)系,然后向新的目標(biāo)節(jié)點(diǎn)發(fā)送命令,目標(biāo)命令執(zhí)行命令并向JedisCluster響應(yīng)
- 如果命令發(fā)送次數(shù)超過5次,則拋出異常"Too many cluster redirection!"
- 基本圖示
全面圖示
6 批量操作
mget、mset須在同一槽。
Redis Cluster不同于Redis 單節(jié)點(diǎn),甚至和一個(gè) Sentinel 監(jiān)控的主從模式也不一樣。主要是因?yàn)榧鹤詣?dòng)分片,將一個(gè)key 映射到16384槽之一,這些槽分布在多節(jié)。因此操作多 key 的命令必須保證所有的key都映射同一槽,避免跨槽執(zhí)行錯(cuò)誤。
一個(gè)單獨(dú)的集群節(jié)點(diǎn),只服務(wù)一組專用的keys,請(qǐng)求一個(gè)命令到一個(gè)Server,只能得到該Server上擁有keys的對(duì)應(yīng)結(jié)果。
一個(gè)非常簡(jiǎn)單的例子是執(zhí)行KEYS命令,當(dāng)發(fā)布該命令到集群中某節(jié)點(diǎn)時(shí),只能得到該節(jié)點(diǎn)上擁有key,并非集群中所有key。要得到集群中所有key,必須從集群的所有主節(jié)點(diǎn)上獲取所有key。
對(duì)于分散在redis集群中不同節(jié)點(diǎn)的數(shù)據(jù),我們?nèi)绾伪容^高效地批量獲取數(shù)據(jù)呢?
6.1 串行mget
定義for循環(huán),遍歷所有key,分別去所有的Redis節(jié)點(diǎn)中獲取值并進(jìn)行匯總,簡(jiǎn)單,但效率不高,需n次網(wǎng)絡(luò)時(shí)間。
6.2 串行I/O
優(yōu)化串行的mget,在客戶端本地做內(nèi)聚,對(duì)每個(gè)key hash,然后取余,知道key對(duì)應(yīng)槽
本地已緩存了槽與節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系,然后對(duì)key按節(jié)點(diǎn)進(jìn)行分組,成立子集,然后使用pipeline把命令發(fā)送到對(duì)應(yīng)的node,需要nodes次網(wǎng)絡(luò)時(shí)間,大大減少了網(wǎng)絡(luò)時(shí)間開銷。
6.3 并行I/O
優(yōu)化串行IO,分組key后,根據(jù)節(jié)點(diǎn)數(shù)量啟動(dòng)對(duì)應(yīng)的線程數(shù),根據(jù)多線程模式并行向node節(jié)點(diǎn)請(qǐng)求數(shù)據(jù),只需1次網(wǎng)絡(luò)時(shí)間
6.4 hash_tag
不做任何改變,hash后就比較均勻地散在每個(gè)節(jié)點(diǎn)上
是否能像單機(jī),一次IO將所有key取出呢?hash-tag提供了這樣功能:若將上述key改為如下,即大括號(hào)括起來相同的內(nèi)容,保證所有的key只向一個(gè)node請(qǐng)求數(shù)據(jù),這樣執(zhí)行類似mget命令只需要去一個(gè)節(jié)點(diǎn)獲取數(shù)據(jù)即可,效率更高。
6.5 選型對(duì)比
第一種方式,使用多線程解決批量問題,減少帶寬時(shí)延,提高效率,這種做法就如上面所說簡(jiǎn)單便捷(我們目前批量操作類型比較多),有效。但問題比較明顯。批量操作數(shù)量不大即可滿足。搜狐的cachecloud采用第二點(diǎn),先將key獲取槽點(diǎn),然后分node pipeline操作。這種做法相對(duì)比第一種做法較優(yōu)。
7 故障轉(zhuǎn)移
7.1 故障發(fā)現(xiàn)
Redis Cluster通過ping/pong消息實(shí)現(xiàn)故障發(fā)現(xiàn):不需要sentinel。ping/pong不僅能傳遞節(jié)點(diǎn)與槽的對(duì)應(yīng)消息,也能傳遞其他狀態(tài),比如:節(jié)點(diǎn)主從狀態(tài),節(jié)點(diǎn)故障等
故障發(fā)現(xiàn)就是通過這種模式來實(shí)現(xiàn),分為主觀下線和客觀下線:
7.1.1 主觀下線
定義
某節(jié)點(diǎn)認(rèn)為另一節(jié)點(diǎn)不可用,這僅代表一個(gè)節(jié)點(diǎn)對(duì)另一節(jié)點(diǎn)的判斷,不代表所有節(jié)點(diǎn)的認(rèn)知。
流程
- 節(jié)點(diǎn)-1定時(shí)發(fā)ping消息給節(jié)點(diǎn)-2
- 若發(fā)送成功,代表節(jié)點(diǎn)-2正常運(yùn)行,節(jié)點(diǎn)-2會(huì)響應(yīng)PONG消息給節(jié)點(diǎn)1,節(jié)點(diǎn)1更新與2的最后通信時(shí)間
- 若發(fā)送失敗,則節(jié)點(diǎn)-1與節(jié)點(diǎn)-2間通信異常判斷連接,在下一定時(shí)任務(wù)周期時(shí),仍然會(huì)與節(jié)點(diǎn)2發(fā)送ping消息
- 若節(jié)點(diǎn)-1發(fā)現(xiàn)與節(jié)點(diǎn)-2最后通信時(shí)間超過node-timeout,則把節(jié)點(diǎn)2標(biāo)識(shí)為pfail狀態(tài)
7.1.2 客觀下線
定義
當(dāng)半數(shù)以上持有槽的主節(jié)點(diǎn)都標(biāo)記某節(jié)點(diǎn)主觀下線??梢员WC判斷的公平性。
集群模式下,只有主節(jié)點(diǎn)(master)才有讀寫權(quán)限和集群槽的維護(hù)權(quán)限,從節(jié)點(diǎn)(slave)只有復(fù)制的權(quán)限。
流程
1.某個(gè)節(jié)點(diǎn)接收到其他節(jié)點(diǎn)發(fā)送的ping消息,如果接收到的ping消息中包含了其他pfail節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)會(huì)將主觀下線的消息內(nèi)容添加到自身的故障列表中,故障列表中包含了當(dāng)前節(jié)點(diǎn)接收到的每一個(gè)節(jié)點(diǎn)對(duì)其他節(jié)點(diǎn)的狀態(tài)信息
2.當(dāng)前節(jié)點(diǎn)把主觀下線的消息內(nèi)容添加到自身的故障列表之后,會(huì)嘗試對(duì)故障節(jié)點(diǎn)進(jìn)行客觀下線操作
7.2 故障恢復(fù)
從節(jié)點(diǎn)接收到它的主節(jié)點(diǎn)客觀下線的通知,則進(jìn)行故障恢復(fù)。
資格檢查
- 對(duì)從節(jié)點(diǎn)的資格進(jìn)行檢查,只有難過檢查的從節(jié)點(diǎn)才可以開始進(jìn)行故障恢復(fù)
- 每個(gè)從節(jié)點(diǎn)檢查與故障主節(jié)點(diǎn)的斷線時(shí)間
- 超過cluster-node-timeout * cluster-slave-validity-factor數(shù)字,則取消資格
- cluster-node-timeout默認(rèn)為15秒,cluster-slave-validity-factor默認(rèn)值為10
- 如果這兩個(gè)參數(shù)都使用默認(rèn)值,則每個(gè)節(jié)點(diǎn)都檢查與故障主節(jié)點(diǎn)的斷線時(shí)間,如果超過150秒,則這個(gè)節(jié)點(diǎn)就沒有成為替換主節(jié)點(diǎn)的可能性
準(zhǔn)備選舉時(shí)間
使偏移量最大的從節(jié)點(diǎn)具備優(yōu)先級(jí)成為主節(jié)點(diǎn)的條件。
選舉投票
對(duì)選舉出來的多個(gè)從節(jié)點(diǎn)進(jìn)行投票,選出新的主節(jié)點(diǎn)。
替換主節(jié)點(diǎn)
- 當(dāng)前從節(jié)點(diǎn)取消復(fù)制變成離節(jié)點(diǎn)。(slaveof no one)
- 執(zhí)行cluster del slot撤銷故障主節(jié)點(diǎn)負(fù)責(zé)的槽,并執(zhí)行cluster add slot把這些槽分配給自己
- 向集群廣播自己的pong消息,表明已經(jīng)替換了故障從節(jié)點(diǎn)
8 開發(fā)運(yùn)維常見問題
8.1 集群完整性
- cluster-require-full-coverage默認(rèn)為yes,即集群中所有節(jié)點(diǎn)都在服務(wù)且16384個(gè)槽都可用,集群才會(huì)提供服務(wù),以保證集群完整性。
- 當(dāng)某節(jié)點(diǎn)故障或者正在故障轉(zhuǎn)移時(shí)獲取數(shù)據(jù)會(huì)提示:(error)CLUSTERDOWN The cluster is down
但是大多數(shù)業(yè)務(wù)都無法容忍,建議把cluster-require-full-coverage設(shè)為no
8.2 帶寬消耗
- Redis Cluster節(jié)點(diǎn)之間會(huì)定期交換Gossip消息,以及做一些心跳檢測(cè)
- 官方建議Redis Cluster節(jié)點(diǎn)數(shù)量不要超過1000個(gè),當(dāng)集群中節(jié)點(diǎn)數(shù)量過多時(shí),會(huì)產(chǎn)生不容忽視的帶寬消耗
- 消息發(fā)送頻率:節(jié)點(diǎn)發(fā)現(xiàn)與其他節(jié)點(diǎn)最后通信時(shí)間超過cluster-node-timeout /2時(shí),會(huì)直接發(fā)送PING消息
- 消息數(shù)據(jù)量:slots槽數(shù)組(2kb空間)和整個(gè)集群1/10的狀態(tài)數(shù)據(jù)(10個(gè)節(jié)點(diǎn)狀態(tài)數(shù)據(jù)約為1kb)
- 節(jié)點(diǎn)部署的機(jī)器規(guī)模:集群分布的機(jī)器越多且每臺(tái)機(jī)器劃分的節(jié)點(diǎn)數(shù)越均勻,則集群內(nèi)整體的可用帶寬越高
帶寬優(yōu)化
- 避免使用’大’集群:避免多業(yè)務(wù)使用一個(gè)集群,大業(yè)務(wù)可以多集群
- cluster-node-timeout:帶寬和故障轉(zhuǎn)移速度的均衡
- 盡量均勻分配到多機(jī)器上:保證高可用和帶寬
8.3 Pub/Sub廣播
- 在任意一個(gè)cluster節(jié)點(diǎn)執(zhí)行publish,則發(fā)布的消息會(huì)在集群中傳播,集群中的其他節(jié)點(diǎn)都會(huì)訂閱到消息,這樣節(jié)點(diǎn)的帶寬的開銷會(huì)很大
- publish在集群每個(gè)節(jié)點(diǎn)廣播,加重帶寬
解決方案
單獨(dú)“走”一套redis sentinel。就是針對(duì)目標(biāo)的幾個(gè)節(jié)點(diǎn)構(gòu)建redis sentinel,在這個(gè)里面實(shí)現(xiàn)廣播。
8.4 集群傾斜
分布式數(shù)據(jù)庫存在傾斜問題是比較常見的。集群傾斜也就是各個(gè)節(jié)點(diǎn)使用的內(nèi)存不一致
數(shù)據(jù)傾斜原因
1.節(jié)點(diǎn)和槽分配不均,如果使用redis-trib.rb工具構(gòu)建集群,則出現(xiàn)這種情況的機(jī)會(huì)不多
- redis-trib.rb info ip:port查看節(jié)點(diǎn),槽,鍵值分布
- redis-trib.rb rebalance ip:port進(jìn)行均衡(謹(jǐn)慎使用)
2.不同槽對(duì)應(yīng)鍵值數(shù)量差異比較大
- CRC16算法正常情況下比較均勻
- 可能存在hash_tag
- cluster countkeysinslot {slot}獲取槽對(duì)應(yīng)鍵值個(gè)數(shù)
3.包含bigkey:例如大字符串,幾百萬的元素的hash,set等
- 在從節(jié)點(diǎn):redis-cli --bigkeys
- 優(yōu)化:優(yōu)化數(shù)據(jù)結(jié)構(gòu)
4.內(nèi)存相關(guān)配置不一致
- hash-max-ziplist-value:滿足一定條件情況下,hash可以使用ziplist
- set-max-intset-entries:滿足一定條件情況下,set可以使用intset
- 在一個(gè)集群內(nèi)有若干個(gè)節(jié)點(diǎn),當(dāng)其中一些節(jié)點(diǎn)配置上面兩項(xiàng)優(yōu)化,另外一部分節(jié)點(diǎn)沒有配置上面兩項(xiàng)優(yōu)化
- 當(dāng)集群中保存hash或者set時(shí),就會(huì)造成節(jié)點(diǎn)數(shù)據(jù)不均勻
- 優(yōu)化:定期檢查配置一致性
5.請(qǐng)求傾斜:熱點(diǎn)key
重要的key或者bigkey
Redis Cluster某個(gè)節(jié)點(diǎn)有一個(gè)非常重要的key,就會(huì)存在熱點(diǎn)問題
優(yōu)化
- 避免bigkey
- 熱鍵不要用hash_tag
- 當(dāng)一致性不高時(shí),可以用本地緩存+ MQ(消息隊(duì)列)
9 讀寫分離
- 只讀連接
- 集群模式下,從節(jié)點(diǎn)不接受任何讀寫請(qǐng)求。
- 當(dāng)向從節(jié)點(diǎn)執(zhí)行讀請(qǐng)求時(shí),重定向到負(fù)責(zé)槽的主節(jié)點(diǎn)
- readonly命令可以讀:連接級(jí)別命令,當(dāng)連接斷開之后,需要再次執(zhí)行
- readonlyredis cluster 默認(rèn)slave 也是不能讀的,如果要讀取,需要執(zhí)行 readonly,就可以了。
讀寫分離:更加復(fù)雜(成本很高,盡量不要使用)
- 同樣的問題:復(fù)制延遲,讀取過期數(shù)據(jù),從節(jié)點(diǎn)故障
- 修改客戶端:cluster slaves {nodeId}
10 集群優(yōu)劣
集群的限制
- key批量操作支持有限:例如mget,mset必須在一個(gè)slot
- key事務(wù)和Lua支持有限:操作的key必須在一個(gè)節(jié)點(diǎn)
- key是數(shù)據(jù)分區(qū)的最小粒度:不支持bigkey分區(qū)
- 不支持多個(gè)數(shù)據(jù)庫:集群模式下只有一個(gè)db0
- 復(fù)制只支持一層:不支持樹形復(fù)制結(jié)構(gòu)
集群不一定好
- Redis Cluster滿足容量和性能的擴(kuò)展性,很多業(yè)務(wù)’不需要’
- 大多數(shù)時(shí)客戶端性能會(huì)’降低’
- 命令無法跨節(jié)點(diǎn)使用:mget,keys,scan,flush,sinter等
- Lua和事務(wù)無法跨節(jié)點(diǎn)使用
- 客戶端維護(hù)更復(fù)雜:SDK和應(yīng)用本身消耗(例如更多的連接池)
- 很多場(chǎng)景Redis Sentinel已經(jīng)夠用了
參考
https://www.slideshare.net/iammutex/redis-cluster
https://zhuanlan.zhihu.com/p/105569485
https://sunweiguo.github.io/2019/02/01/redis/Redis-Cluster%E7%90%86%E8%AE%BA%E8%AF%A6%E8%A7%A3/
https://redis.io/topics/cluster-spec
http://trumandu.github.io/2016/05/09/RedisCluster%E6%9E%84%E5%BB%BA%E6%89%B9%E9%87%8F%E6%93%8D%E4%BD%9C%E6%8E%A2%E8%AE%A8/