溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Cluster集群能支撐的數(shù)據(jù)有多大

發(fā)布時(shí)間:2021-06-26 13:49:05 來(lái)源:億速云 閱讀:158 作者:chen 欄目:web開(kāi)發(fā)

這篇文章主要講解了“Cluster集群能支撐的數(shù)據(jù)有多大”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Cluster集群能支撐的數(shù)據(jù)有多大”吧!

本文將對(duì)集群的節(jié)點(diǎn)、槽指派、命令執(zhí)行、重新分片、轉(zhuǎn)向、故障轉(zhuǎn)移、消息等各個(gè)方面進(jìn)行深入拆解。

Cluster集群能支撐的數(shù)據(jù)有多大

Redis 集群原理總覽

目的在于掌握什么是 Cluster ?Cluster 分片原理,客戶(hù)端定位數(shù)據(jù)原理、故障切換,選主,什么場(chǎng)景使用 Cluster,如何部署集群  …...

  • 將數(shù)據(jù)分成多份存在不同實(shí)例上

  • 哈希槽與 Redis 實(shí)例映射

  • 復(fù)制與故障轉(zhuǎn)移

  • 故障檢測(cè)

  • 故障轉(zhuǎn)移

  • 選主流程

  • 用表保存鍵值對(duì)和實(shí)例的關(guān)聯(lián)關(guān)系可行么

  • 重新分配哈希槽

  • MOVED 錯(cuò)誤

  • ASK 錯(cuò)誤

  • Gossip 消息

  • 實(shí)例的通信頻率

  • 降低實(shí)例間的通信開(kāi)銷(xiāo)

為什么需要 Cluster“

  • 65 哥:碼哥,自從用上了你說(shuō)的哨兵集群實(shí)現(xiàn)故障自動(dòng)轉(zhuǎn)移后,我終于可以開(kāi)心的跟女朋友么么噠也不怕 Redis 宕機(jī)深夜宕機(jī)了。

  • 可是最近遇到一個(gè)糟心的問(wèn)題,Redis 需要保存 800 萬(wàn)個(gè)鍵值對(duì),占用 20 GB 的內(nèi)存。

  • 我就使用了一臺(tái) 32G 的內(nèi)存主機(jī)部署,但是 Redis 響應(yīng)有時(shí)候非常慢,使用 INFO 命令查看 latest_fork_usec 指標(biāo)(最近一次  fork 耗時(shí)),發(fā)現(xiàn)特別高。

主要是 Redis RDB 持久化機(jī)制導(dǎo)致的,Redis 會(huì) Fork 子進(jìn)程完成 RDB 持久化操作,fork 執(zhí)行的耗時(shí)與 Redis  數(shù)據(jù)量成正相關(guān)。

而 Fork 執(zhí)行的時(shí)候會(huì)阻塞主線(xiàn)程,由于數(shù)據(jù)量過(guò)大導(dǎo)致阻塞主線(xiàn)程過(guò)長(zhǎng),所以出現(xiàn)了 Redis 響應(yīng)慢的表象。

  • 65 哥:隨著業(yè)務(wù)規(guī)模的拓展,數(shù)據(jù)量越來(lái)越大。主從架構(gòu)升級(jí)單個(gè)實(shí)例硬件難以拓展,且保存大數(shù)據(jù)量會(huì)導(dǎo)致響應(yīng)慢問(wèn)題,有什么辦法可以解決么?

保存大量數(shù)據(jù),除了使用大內(nèi)存主機(jī)的方式,我們還可以使用切片集群。俗話(huà)說(shuō)「眾人拾材火焰高」,一臺(tái)機(jī)器無(wú)法保存所有數(shù)據(jù),那就多臺(tái)分擔(dān)。

使用 Redis Cluster 集群,主要解決了大數(shù)據(jù)量存儲(chǔ)導(dǎo)致的各種慢問(wèn)題,同時(shí)也便于橫向拓展。

兩種方案對(duì)應(yīng)著 Redis 數(shù)據(jù)增多的兩種拓展方案:垂直擴(kuò)展(scale up)、水平擴(kuò)展(scale out)。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 垂直拓展:升級(jí)單個(gè) Redis 的硬件配置,比如增加內(nèi)存容量、磁盤(pán)容量、使用更強(qiáng)大的 CPU。

  3. 水平拓展:橫向增加 Redis 實(shí)例個(gè)數(shù),每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分?jǐn)?shù)據(jù)。

比如需要一個(gè)內(nèi)存 24 GB 磁盤(pán) 150 GB 的服務(wù)器資源,有以下兩種方案:

Cluster集群能支撐的數(shù)據(jù)有多大

水平拓展與垂直拓展

在面向百萬(wàn)、千萬(wàn)級(jí)別的用戶(hù)規(guī)模時(shí),橫向擴(kuò)展的 Redis 切片集群會(huì)是一個(gè)非常好的選擇。

65 哥:那這兩種方案都有什么優(yōu)缺點(diǎn)呢?

  • 垂直拓展部署簡(jiǎn)單,但是當(dāng)數(shù)據(jù)量大并且使用 RDB 實(shí)現(xiàn)持久化,會(huì)造成阻塞導(dǎo)致響應(yīng)慢。另外受限于硬件和成本,拓展內(nèi)存的成本太大,比如拓展到 1T  內(nèi)存。

  • 水平拓展便于拓展,同時(shí)不需要擔(dān)心單個(gè)實(shí)例的硬件和成本的限制。但是,切片集群會(huì)涉及多個(gè)實(shí)例的分布式管理問(wèn)題,需要解決如何將數(shù)據(jù)合理分布到不同實(shí)例,同時(shí)還要讓客戶(hù)端能正確訪(fǎng)問(wèn)到實(shí)例上的數(shù)據(jù)。

什么是 Cluster 集群

Redis  集群是一種分布式數(shù)據(jù)庫(kù)方案,集群通過(guò)分片(sharding)來(lái)進(jìn)行數(shù)據(jù)管理(「分治思想」的一種實(shí)踐),并提供復(fù)制和故障轉(zhuǎn)移功能。

將數(shù)據(jù)劃分為 16384 的 slots,每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分槽位。槽位的信息存儲(chǔ)于每個(gè)節(jié)點(diǎn)中。

它是去中心化的,如圖所示,該集群有三個(gè) Redis 節(jié)點(diǎn)組成,每個(gè)節(jié)點(diǎn)負(fù)責(zé)整個(gè)集群的一部分?jǐn)?shù)據(jù),每個(gè)節(jié)點(diǎn)負(fù)責(zé)的數(shù)據(jù)多少可能不一樣。

Cluster集群能支撐的數(shù)據(jù)有多大

Redis 集群架構(gòu)

三個(gè)節(jié)點(diǎn)相互連接組成一個(gè)對(duì)等的集群,它們之間通過(guò) Gossip協(xié)議相互交互集群信息,最后每個(gè)節(jié)點(diǎn)都保存著其他節(jié)點(diǎn)的 slots 分配情況。

開(kāi)篇寄語(yǔ)

技術(shù)不是萬(wàn)能的,程序員也不是最厲害的,一定要搞清楚,不要覺(jué)得「老子天下第一」。一旦有了這個(gè)意識(shí),可能會(huì)耽誤我們的成長(zhǎng)。

技術(shù)是為了解決問(wèn)題的,如果說(shuō)一個(gè)技術(shù)不能解決問(wèn)題,那這個(gè)技術(shù)就一文不值。

不要去炫技,沒(méi)有意義。

集群安裝

  • 點(diǎn)擊 -> 《Redis 6.X Cluster 集群搭建》查看

一個(gè) Redis  集群通常由多個(gè)節(jié)點(diǎn)(node)組成,在剛開(kāi)始的時(shí)候,每個(gè)節(jié)點(diǎn)都是相互獨(dú)立的,它們都處于一個(gè)只包含自己的集群當(dāng)中,要組建一個(gè)真正可工作的集群,我們必須將各個(gè)獨(dú)立的節(jié)點(diǎn)連接起來(lái),構(gòu)成一個(gè)包含多個(gè)節(jié)點(diǎn)的集群。

連接各個(gè)節(jié)點(diǎn)的工作可以通過(guò) CLUSTER MEET 命令完成:CLUSTER MEET。

向一個(gè)節(jié)點(diǎn) node 發(fā)送 CLUSTER MEET 命令,可以讓 node 節(jié)點(diǎn)與 ip 和 port  所指定的節(jié)點(diǎn)進(jìn)行握手(handshake),當(dāng)握手成功時(shí),node 節(jié)點(diǎn)就會(huì)將 ip 和 port 所指定的節(jié)點(diǎn)添加到 node 節(jié)點(diǎn)當(dāng)前所在的集群中。

 Cluster集群能支撐的數(shù)據(jù)有多大

CLUSTER MEET

就好像 node 節(jié)點(diǎn)說(shuō):“喂,ip = xx,port = xx  的老哥,要不要加入「碼哥字節(jié)」技術(shù)群,加入集群就找到了一條大神成長(zhǎng)之路,關(guān)注「碼哥字節(jié)」公眾號(hào)回復(fù)「加群」,是兄弟就跟我一起來(lái)!”

關(guān)于 Redis Cluster 集群搭建詳細(xì)步驟,請(qǐng)點(diǎn)擊文末左下角「閱讀原文」或者點(diǎn)擊 -> 《Redis 6.X Cluster  集群搭建》查看,官方關(guān)于 Redis Cluster 的詳情請(qǐng)看:https://redis.io/topics/cluster-tutorial。

Cluster 實(shí)現(xiàn)原理

65 哥:數(shù)據(jù)切片后,需要將數(shù)據(jù)分布在不同實(shí)例上,數(shù)據(jù)和實(shí)例之間如何對(duì)應(yīng)上呢?

”Redis 3.0 開(kāi)始,官方提供了 Redis Cluster 方案實(shí)現(xiàn)了切片集群,該方案就實(shí)現(xiàn)了數(shù)據(jù)和實(shí)例的規(guī)則。Redis Cluster  方案采用哈希槽(Hash Slot,接下來(lái)我會(huì)直接稱(chēng)之為 Slot),來(lái)處理數(shù)據(jù)和實(shí)例之間的映射關(guān)系。

跟著「碼哥字節(jié)」一起進(jìn)入 Cluster 實(shí)現(xiàn)原理探索之旅…...

將數(shù)據(jù)分成多份存在不同實(shí)例上

集群的整個(gè)數(shù)據(jù)庫(kù)被分為 16384 個(gè)槽(slot),數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這 16384  個(gè)槽的其中一個(gè),集群中的每個(gè)節(jié)點(diǎn)可以處理 0 個(gè)或最多 16384 個(gè)槽。

Key 與哈希槽映射過(guò)程可以分為兩大步驟:

根據(jù)鍵值對(duì)的 key,使用 CRC16 算法,計(jì)算出一個(gè) 16 bit 的值;

將 16 bit 的值對(duì) 16384 執(zhí)行取模,得到 0 ~ 16383 的數(shù)表示 key 對(duì)應(yīng)的哈希槽。

Cluster 還允許用戶(hù)強(qiáng)制某個(gè) key 掛在特定槽位上,通過(guò)在 key 字符串里面嵌入 tag 標(biāo)記,這就可以強(qiáng)制 key 所掛在的槽位等于 tag  所在的槽位。

哈希槽與 Redis 實(shí)例映射

65 哥:哈希槽又是如何映射到 Redis 實(shí)例上呢?

”在 部署集群的樣例中通過(guò) cluster create 創(chuàng)建,Redis 會(huì)自動(dòng)將 16384 個(gè) 哈希槽平均分布在集群實(shí)例上,比如 N  個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上的哈希槽數(shù) = 16384 / N 個(gè)。

除此之外,可以通過(guò) CLUSTER MEET 命令將 7000、7001、7002  三個(gè)節(jié)點(diǎn)連在一個(gè)集群,但是集群目前依然處于下線(xiàn)狀態(tài),因?yàn)槿齻€(gè)實(shí)例都沒(méi)有處理任何哈希槽。

可以使用 cluster addslots 命令,指定每個(gè)實(shí)例上的哈希槽個(gè)數(shù)。

65 哥:為啥要手動(dòng)制定呢?

能者多勞嘛,加入集群中的 Redis 實(shí)例配置不一樣,如果承擔(dān)一樣的壓力,對(duì)于垃圾機(jī)器來(lái)說(shuō)就太難了,讓牛逼的機(jī)器多支持一點(diǎn)。

三個(gè)實(shí)例的集群,通過(guò)下面的指令為每個(gè)實(shí)例分配哈希槽:實(shí)例 1負(fù)責(zé) 0 ~ 5460 哈希槽,實(shí)例 2 負(fù)責(zé) 5461~10922 哈希槽,實(shí)例 3 負(fù)責(zé)  10923 ~ 16383 哈希槽。

redis-cli -h 172.16.19.1 –p 6379 cluster addslots 0,5460 redis-cli -h 172.16.19.2 –p 6379 cluster addslots 5461,10922 redis-cli -h 172.16.19.3 –p 6379 cluster addslots 10923,16383

鍵值對(duì)數(shù)據(jù)、哈希槽、Redis 實(shí)例之間的映射關(guān)系如下:

Cluster集群能支撐的數(shù)據(jù)有多大

數(shù)據(jù)、Slot與實(shí)例的映射

Redis 鍵值對(duì)的 key 「碼哥字節(jié)」「牛逼」經(jīng)過(guò) CRC16 計(jì)算后再對(duì)哈希槽總個(gè)數(shù) 16394 取模,模數(shù)結(jié)果分別映射到實(shí)例 1 與實(shí)例 2  上。

切記,當(dāng) 16384 個(gè)槽都分配完全,Redis 集群才能正常工作。

復(fù)制與故障轉(zhuǎn)移

65 哥:Redis 集群如何實(shí)現(xiàn)高可用呢?Master 與 Slave 還是讀寫(xiě)分離么?

Master 用于處理槽,Slave 節(jié)點(diǎn)則通過(guò)《Redis 主從架構(gòu)數(shù)據(jù)同步》方式同步主節(jié)點(diǎn)數(shù)據(jù)。

當(dāng) Master 下線(xiàn),Slave 代替主節(jié)點(diǎn)繼續(xù)處理請(qǐng)求。主從節(jié)點(diǎn)之間并沒(méi)有讀寫(xiě)分離, Slave 只用作 Master 宕機(jī)的高可用備份。

Redis Cluster 可以為每個(gè)主節(jié)點(diǎn)設(shè)置若干個(gè)從節(jié)點(diǎn),單主節(jié)點(diǎn)故障時(shí),集群會(huì)自動(dòng)將其中某個(gè)從節(jié)點(diǎn)提升為主節(jié)點(diǎn)。

如果某個(gè)主節(jié)點(diǎn)沒(méi)有從節(jié)點(diǎn),那么當(dāng)它發(fā)生故障時(shí),集群將完全處于不可用狀態(tài)。

不過(guò) Redis 也提供了一個(gè)參數(shù)cluster-require-full-coverage可以允許部分節(jié)點(diǎn)故障,其它節(jié)點(diǎn)還可以繼續(xù)提供對(duì)外訪(fǎng)問(wèn)。

比如 7000 主節(jié)點(diǎn)宕機(jī),作為 slave 的 7003 成為 Master 節(jié)點(diǎn)繼續(xù)提供服務(wù)。當(dāng)下線(xiàn)的節(jié)點(diǎn) 7000 重新上線(xiàn),它將成為當(dāng)前  70003 的從節(jié)點(diǎn)。

故障檢測(cè)

65 哥:在《Redis 高可用篇:Sentinel 哨兵集群原理》我知道哨兵通過(guò)監(jiān)控、自動(dòng)切換主庫(kù)、通知客戶(hù)端實(shí)現(xiàn)故障自動(dòng)切換,Cluster  又如何實(shí)現(xiàn)故障自動(dòng)轉(zhuǎn)移呢?

一個(gè)節(jié)點(diǎn)認(rèn)為某個(gè)節(jié)點(diǎn)失聯(lián)了并不代表所有的節(jié)點(diǎn)都認(rèn)為它失聯(lián)了。只有當(dāng)大多數(shù)負(fù)責(zé)處理 slot  節(jié)點(diǎn)都認(rèn)定了某個(gè)節(jié)點(diǎn)下線(xiàn)了,集群才認(rèn)為該節(jié)點(diǎn)需要進(jìn)行主從切換。

Redis 集群節(jié)點(diǎn)采用 Gossip 協(xié)議來(lái)廣播自己的狀態(tài)以及自己對(duì)整個(gè)集群認(rèn)知的改變。比如一個(gè)節(jié)點(diǎn)發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)失聯(lián)了  (PFail),它會(huì)將這條信息向整個(gè)集群廣播,其它節(jié)點(diǎn)也就可以收到這點(diǎn)失聯(lián)信息。

關(guān)于 Gossip 協(xié)議可閱讀悟空哥的一篇文章:《病毒入侵,全靠分布式》

如果一個(gè)節(jié)點(diǎn)收到了某個(gè)節(jié)點(diǎn)失聯(lián)的數(shù)量 (PFail Count) 已經(jīng)達(dá)到了集群的大多數(shù),就可以標(biāo)記該節(jié)點(diǎn)為確定下線(xiàn)狀態(tài)  (Fail),然后向整個(gè)集群廣播,強(qiáng)迫其它節(jié)點(diǎn)也接收該節(jié)點(diǎn)已經(jīng)下線(xiàn)的事實(shí),并立即對(duì)該失聯(lián)節(jié)點(diǎn)進(jìn)行主從切換。

故障轉(zhuǎn)移

當(dāng)一個(gè) Slave 發(fā)現(xiàn)自己的主節(jié)點(diǎn)進(jìn)入已下線(xiàn)狀態(tài)后,從節(jié)點(diǎn)將開(kāi)始對(duì)下線(xiàn)的主節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 從下線(xiàn)的 Master 及節(jié)點(diǎn)的 Slave 節(jié)點(diǎn)列表選擇一個(gè)節(jié)點(diǎn)成為新主節(jié)點(diǎn)。

  3. 新主節(jié)點(diǎn)會(huì)撤銷(xiāo)所有對(duì)已下線(xiàn)主節(jié)點(diǎn)的 slot 指派,并將這些 slots 指派給自己。

  4. 新的主節(jié)點(diǎn)向集群廣播一條 PONG 消息,這條 PONG  消息可以讓集群中的其他節(jié)點(diǎn)立即知道這個(gè)節(jié)點(diǎn)已經(jīng)由從節(jié)點(diǎn)變成了主節(jié)點(diǎn),并且這個(gè)主節(jié)點(diǎn)已經(jīng)接管了原本由已下線(xiàn)節(jié)點(diǎn)負(fù)責(zé)處理的槽。

  5. 新的主節(jié)點(diǎn)開(kāi)始接收處理槽有關(guān)的命令請(qǐng)求,故障轉(zhuǎn)移完成。

選主流程

65 哥:新的主節(jié)點(diǎn)如何選舉產(chǎn)生的?

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 集群的配置紀(jì)元 +1,是一個(gè)自曾計(jì)數(shù)器,初始值 0 ,每次執(zhí)行故障轉(zhuǎn)移都會(huì) +1。

  3. 檢測(cè)到主節(jié)點(diǎn)下線(xiàn)的從節(jié)點(diǎn)向集群廣播一條CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有收到這條消息、并且具有投票權(quán)的主節(jié)點(diǎn)向這個(gè)從節(jié)點(diǎn)投票。

  4. 這個(gè)主節(jié)點(diǎn)尚未投票給其他從節(jié)點(diǎn),那么主節(jié)點(diǎn)將向要求投票的從節(jié)點(diǎn)返回一條CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示這個(gè)主節(jié)點(diǎn)支持從節(jié)點(diǎn)成為新的主節(jié)點(diǎn)。

  5. 參與選舉的從節(jié)點(diǎn)都會(huì)接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,如果收集到的票 >= (N/2) + 1  支持,那么這個(gè)從節(jié)點(diǎn)就被選舉為新主節(jié)點(diǎn)。

  6. 如果在一個(gè)配置紀(jì)元里面沒(méi)有從節(jié)點(diǎn)能收集到足夠多的支持票,那么集群進(jìn)入一個(gè)新的配置紀(jì)元,并再次進(jìn)行選舉,直到選出新的主節(jié)點(diǎn)為止。

跟哨兵類(lèi)似,兩者都是基于 Raft 算法來(lái)實(shí)現(xiàn)的,流程如圖所示:

 Cluster集群能支撐的數(shù)據(jù)有多大

集群Leader選舉

用表保存鍵值對(duì)和實(shí)例的關(guān)聯(lián)關(guān)系可行么

65 哥,我來(lái)考考你:“Redis Cluster 方案通過(guò)哈希槽的方式把鍵值對(duì)分配到不同的實(shí)例上,這個(gè)過(guò)程需要對(duì)鍵值對(duì)的 key 做 CRC 計(jì)算并對(duì)  哈希槽總數(shù)取模映射到實(shí)例上。如果用一個(gè)表直接把鍵值對(duì)和實(shí)例的對(duì)應(yīng)關(guān)系記錄下來(lái)(例如鍵值對(duì) 1 在實(shí)例 2 上,鍵值對(duì) 2 在實(shí)例 1 上),這樣就不用計(jì)算  key 和哈希槽的對(duì)應(yīng)關(guān)系了,只用查表就行了,Redis 為什么不這么做呢?”

使用一個(gè)全局表記錄的話(huà),假如鍵值對(duì)和實(shí)例之間的關(guān)系改變(重新分片、實(shí)例增減),需要修改表。如果是單線(xiàn)程操作,所有操作都要串行,性能太慢。

多線(xiàn)程的話(huà),就涉及到加鎖,另外,如果鍵值對(duì)數(shù)據(jù)量非常大,保存鍵值對(duì)與實(shí)例關(guān)系的表數(shù)據(jù)所需要的存儲(chǔ)空間也會(huì)很大。

而哈希槽計(jì)算,雖然也要記錄哈希槽與實(shí)例時(shí)間的關(guān)系,但是哈希槽的數(shù)量少得多,只有 16384 個(gè),開(kāi)銷(xiāo)很小。

客戶(hù)端如何定位數(shù)據(jù)所在實(shí)例

65 哥:客戶(hù)端又怎么確定訪(fǎng)問(wèn)的數(shù)據(jù)到底分布在哪個(gè)實(shí)例上呢?

Redis 實(shí)例會(huì)將自己的哈希槽信息通過(guò) Gossip 協(xié)議發(fā)送給集群中其他的實(shí)例,實(shí)現(xiàn)了哈希槽分配信息的擴(kuò)散。

這樣,集群中的每個(gè)實(shí)例都有所有哈希槽與實(shí)例之間的映射關(guān)系信息。

在切片數(shù)據(jù)的時(shí)候是將 key 通過(guò) CRC16 計(jì)算出一個(gè)值再對(duì) 16384 取模得到對(duì)應(yīng)的  Slot,這個(gè)計(jì)算任務(wù)可以在客戶(hù)端上執(zhí)行發(fā)送請(qǐng)求的時(shí)候執(zhí)行。

但是,定位到槽以后還需要進(jìn)一步定位到該 Slot 所在 Redis 實(shí)例。

當(dāng)客戶(hù)端連接任何一個(gè)實(shí)例,實(shí)例就將哈希槽與實(shí)例的映射關(guān)系響應(yīng)給客戶(hù)端,客戶(hù)端就會(huì)將哈希槽與實(shí)例映射信息緩存在本地。

當(dāng)客戶(hù)端請(qǐng)求時(shí),會(huì)計(jì)算出鍵所對(duì)應(yīng)的哈希槽,在通過(guò)本地緩存的哈希槽實(shí)例映射信息定位到數(shù)據(jù)所在實(shí)例上,再將請(qǐng)求發(fā)送給對(duì)應(yīng)的實(shí)例。

Cluster集群能支撐的數(shù)據(jù)有多大

Redis 客戶(hù)端定位數(shù)據(jù)所在節(jié)點(diǎn)

重新分配哈希槽

65 哥:哈希槽與實(shí)例之間的映射關(guān)系由于新增實(shí)例或者負(fù)載均衡重新分配導(dǎo)致改變了咋辦?

集群中的實(shí)例通過(guò) Gossip 協(xié)議互相傳遞消息獲取最新的哈希槽分配信息,但是,客戶(hù)端無(wú)法感知。

Redis Cluster 提供了重定向機(jī)制:客戶(hù)端將請(qǐng)求發(fā)送到實(shí)例上,這個(gè)實(shí)例沒(méi)有相應(yīng)的數(shù)據(jù),該 Redis  實(shí)例會(huì)告訴客戶(hù)端將請(qǐng)求發(fā)送到其他的實(shí)例上。

65 哥:Redis 如何告知客戶(hù)端重定向訪(fǎng)問(wèn)新實(shí)例呢?

分為兩種情況:MOVED 錯(cuò)誤、ASK 錯(cuò)誤。

MOVED 錯(cuò)誤

MOVED 錯(cuò)誤(負(fù)載均衡,數(shù)據(jù)已經(jīng)遷移到其他實(shí)例上):當(dāng)客戶(hù)端將一個(gè)鍵值對(duì)操作請(qǐng)求發(fā)送給某個(gè)實(shí)例,而這個(gè)鍵所在的槽并非由自己負(fù)責(zé)的時(shí)候,該實(shí)例會(huì)返回一個(gè)  MOVED 錯(cuò)誤指引轉(zhuǎn)向正在負(fù)責(zé)該槽的節(jié)點(diǎn)。

GET 公眾號(hào):碼哥字節(jié) (error) MOVED 16330 172.17.18.2:6379

該響應(yīng)表示客戶(hù)端請(qǐng)求的鍵值對(duì)所在的哈希槽 16330 遷移到了 172.17.18.2 這個(gè)實(shí)例上,端口是 6379。這樣客戶(hù)端就與  172.17.18.2:6379 建立連接,并發(fā)送 GET 請(qǐng)求。

同時(shí),客戶(hù)端還會(huì)更新本地緩存,將該 slot 與 Redis 實(shí)例對(duì)應(yīng)關(guān)系更新正確。

Cluster集群能支撐的數(shù)據(jù)有多大

MOVED 指令

ASK 錯(cuò)誤

65 哥:如果某個(gè) slot 的數(shù)據(jù)比較多,部分遷移到新實(shí)例,還有一部分沒(méi)有遷移咋辦?

如果請(qǐng)求的 key 在當(dāng)前節(jié)點(diǎn)找到就直接執(zhí)行命令,否則時(shí)候就需要 ASK 錯(cuò)誤響應(yīng)了,槽部分遷移未完成的情況下,如果需要訪(fǎng)問(wèn)的 key 所在 Slot  正在從從 實(shí)例 1 遷移到 實(shí)例 2,實(shí)例 1 會(huì)返回客戶(hù)端一條 ASK 報(bào)錯(cuò)信息:客戶(hù)端請(qǐng)求的 key 所在的哈希槽正在遷移到實(shí)例 2 上,你先給實(shí)例 2  發(fā)送一個(gè) ASKING 命令,接著發(fā)發(fā)送操作命令。

GET 公眾號(hào):碼哥字節(jié) (error) ASK 16330 172.17.18.2:6379

比如客戶(hù)端請(qǐng)求定位到 key = 「公眾號(hào):碼哥字節(jié)」的槽 16330 在實(shí)例 172.17.18.1 上,節(jié)點(diǎn) 1 如果找得到就直接執(zhí)行命令,否則響應(yīng)  ASK 錯(cuò)誤信息,并指引客戶(hù)端轉(zhuǎn)向正在遷移的目標(biāo)節(jié)點(diǎn) 172.17.18.2。

 Cluster集群能支撐的數(shù)據(jù)有多大

ASK 錯(cuò)誤

注意:ASK 錯(cuò)誤指令并不會(huì)更新客戶(hù)端緩存的哈希槽分配信息。

所以客戶(hù)端再次請(qǐng)求 Slot 16330 的數(shù)據(jù),還是會(huì)先給 172.17.18.1 實(shí)例發(fā)送請(qǐng)求,只不過(guò)節(jié)點(diǎn)會(huì)響應(yīng) ASK  命令讓客戶(hù)端給新實(shí)例發(fā)送一次請(qǐng)求。

MOVED指令則更新客戶(hù)端本地緩存,讓后續(xù)指令都發(fā)往新實(shí)例。

集群可以設(shè)置多大?

65 哥:有了 Redis Cluster,再也不怕大數(shù)據(jù)量了,我可以無(wú)限水平拓展么?

答案是否定的,Redis 官方給的 Redis Cluster 的規(guī)模上線(xiàn)是 1000 個(gè)實(shí)例。

65 哥:到底是什么限制了集群規(guī)模呢?

關(guān)鍵在于實(shí)例間的通信開(kāi)銷(xiāo),Cluster 集群中的每個(gè)實(shí)例都保存所有哈希槽與實(shí)例對(duì)應(yīng)關(guān)系信息(Slot 映射到節(jié)點(diǎn)的表),以及自身的狀態(tài)信息。

在集群之間每個(gè)實(shí)例通過(guò) Gossip協(xié)議傳播節(jié)點(diǎn)的數(shù)據(jù),Gossip 協(xié)議工作原理大概如下:

從集群中隨機(jī)選擇一些實(shí)例按照一定的頻率發(fā)送 PING 消息發(fā)送給挑選出來(lái)的實(shí)例,用于檢測(cè)實(shí)例狀態(tài)以及交換彼此的信息。PING  消息中封裝了發(fā)送者自身的狀態(tài)信息、部分其他實(shí)例的狀態(tài)信息、Slot 與實(shí)例映射表信息。

實(shí)例接收到 PING 消息后,響應(yīng) PONG 消息,消息包含的信息跟 PING 消息一樣。

集群之間通過(guò) Gossip協(xié)議可以在一段時(shí)間之后每個(gè)實(shí)例都能獲取其他所有實(shí)例的狀態(tài)信息。

所以在有新節(jié)點(diǎn)加入,節(jié)點(diǎn)故障,Slot 映射變更都可以通過(guò) PING,PONG 的消息傳播完成集群狀態(tài)在每個(gè)實(shí)例的傳播同步。

Gossip 消息

發(fā)送的消息結(jié)構(gòu)是 clusterMsgDataGossip結(jié)構(gòu)體組成:

typedef struct {     char nodename[CLUSTER_NAMELEN];  //40字節(jié)     uint32_t ping_sent; //4字節(jié)     uint32_t pong_received; //4字節(jié)     char ip[NET_IP_STR_LEN]; //46字節(jié)     uint16_t port;  //2字節(jié)     uint16_t cport;  //2字節(jié)     uint16_t flags;  //2字節(jié)     uint32_t notused1; //4字節(jié) } clusterMsgDataGossip;

所以每個(gè)實(shí)例發(fā)送一個(gè) Gossip消息,就需要發(fā)送 104 字節(jié)。如果集群是 1000 個(gè)實(shí)例,那么每個(gè)實(shí)例發(fā)送一個(gè) PING 消息則會(huì)占用 大約  10KB。

除此之外,實(shí)例間在傳播 Slot 映射表的時(shí)候,每個(gè)消息還包含了 一個(gè)長(zhǎng)度為 16384 bit 的 Bitmap。

每一位對(duì)應(yīng)一個(gè) Slot,如果值 = 1 則表示這個(gè) Slot 屬于當(dāng)前實(shí)例,這個(gè) Bitmap 占用 2KB,所以一個(gè) PING 消息大約  12KB。

PONG與PING 消息一樣,一發(fā)一回兩個(gè)消息加起來(lái)就是 24  KB。集群規(guī)模的增加,心跳消息越來(lái)越多就會(huì)占據(jù)集群的網(wǎng)絡(luò)通信帶寬,降低了集群吞吐量。

實(shí)例的通信頻率

65 哥:碼哥,發(fā)送 PING 消息的頻率也會(huì)影響集群帶寬吧?

Redis Cluster 的實(shí)例啟動(dòng)后,默認(rèn)會(huì)每秒從本地的實(shí)例列表中隨機(jī)選出 5 個(gè)實(shí)例,再?gòu)倪@ 5 個(gè)實(shí)例中找出一個(gè)最久沒(méi)有收到 PING  消息的實(shí)例,把 PING 消息發(fā)送給該實(shí)例。

65 哥:隨機(jī)選擇 5 個(gè),但是無(wú)法保證選中的是整個(gè)集群最久沒(méi)有收到 PING  通信的實(shí)例,有的實(shí)例可能一直沒(méi)有收到消息,導(dǎo)致他們維護(hù)的集群信息早就過(guò)期了,咋辦呢?

”這個(gè)問(wèn)題問(wèn)的好,Redis Cluster 的實(shí)例每 100 ms 就會(huì)掃描本地實(shí)例列表,當(dāng)發(fā)現(xiàn)有實(shí)例最近一次收到 PONG 消息的時(shí)間 >  cluster-node-timeout / 2。那么就立刻給這個(gè)實(shí)例發(fā)送 PING 消息,更新這個(gè)節(jié)點(diǎn)的集群狀態(tài)信息。

當(dāng)集群規(guī)模變大,就會(huì)進(jìn)一步導(dǎo)致實(shí)例間網(wǎng)絡(luò)通信延遲怎加。可能會(huì)引起更多的 PING 消息頻繁發(fā)送。

降低實(shí)例間的通信開(kāi)銷(xiāo)

  • 每個(gè)實(shí)例每秒發(fā)送一條 PING消息,降低這個(gè)頻率可能會(huì)導(dǎo)致集群每個(gè)實(shí)例的狀態(tài)信息無(wú)法及時(shí)傳播。

  • 每 100 ms 檢測(cè)實(shí)例 PONG消息接收是否超過(guò) cluster-node-timeout / 2,這個(gè)是 Redis  實(shí)例默認(rèn)的周期性檢測(cè)任務(wù)頻率,我們不會(huì)輕易修改。

所以,只能修改 cluster-node-timeout的值:集群中判斷實(shí)例是否故障的心跳時(shí)間,默認(rèn) 15 S。

所以,為了避免過(guò)多的心跳消息占用集群寬帶,將 cluster-node-timeout調(diào)成 20 秒或者 30 秒,這樣 PONG  消息接收超時(shí)的情況就會(huì)緩解。

但是,也不能設(shè)置的太大。都則就會(huì)導(dǎo)致實(shí)例發(fā)生故障了,卻要等待 cluster-node-timeout時(shí)長(zhǎng)才能檢測(cè)出這個(gè)故障,影響集群正常服務(wù)、

總結(jié)

《Redis 系列》至今已發(fā)布 7 篇,每一篇「碼哥字節(jié)」都耗費(fèi)大量精力,精益求精。確保每一篇都給讀者帶來(lái)價(jià)值,讓大家得到真正的提升。

  • 哨兵集群實(shí)現(xiàn)故障自動(dòng)轉(zhuǎn)移,但是當(dāng)數(shù)據(jù)量過(guò)大導(dǎo)致生成 RDB 時(shí)間過(guò)長(zhǎng)。而 Fork 執(zhí)行的時(shí)候會(huì)阻塞主線(xiàn)程,由于數(shù)據(jù)量過(guò)大導(dǎo)致阻塞主線(xiàn)程過(guò)長(zhǎng),所以出現(xiàn)了  Redis 響應(yīng)慢的表象。

  • 使用 Redis Cluster 集群,主要解決了大數(shù)據(jù)量存儲(chǔ)導(dǎo)致的各種慢問(wèn)題,同時(shí)也便于橫向拓展。在面向百萬(wàn)、千萬(wàn)級(jí)別的用戶(hù)規(guī)模時(shí),橫向擴(kuò)展的  Redis 切片集群會(huì)是一個(gè)非常好的選擇。

  • 集群的整個(gè)數(shù)據(jù)庫(kù)被分為 16384 個(gè)槽(slot),數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這 16384 個(gè)槽的其中一個(gè),集群中的每個(gè)節(jié)點(diǎn)可以處理 0 個(gè)或最多  16384 個(gè)槽。

  • Redis 集群節(jié)點(diǎn)采用 Gossip 協(xié)議來(lái)廣播自己的狀態(tài)以及自己對(duì)整個(gè)集群認(rèn)知的改變。

  • 客戶(hù)端連接到集群候任何一個(gè)實(shí)例后,實(shí)例會(huì)將哈希槽與實(shí)例映射信息發(fā)送給客戶(hù)端,客戶(hù)端將信息保存,用于將 key 定位到對(duì)應(yīng)的節(jié)點(diǎn)。

  • 集群并不能無(wú)限增加,由于集群通過(guò) Gossip協(xié)議傳播集群實(shí)例信息,所以通信頻率是限制集群大小的主要原因,主要可以通過(guò)修改  cluster-node-timeout調(diào)整頻率。

感謝各位的閱讀,以上就是“Cluster集群能支撐的數(shù)據(jù)有多大”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Cluster集群能支撐的數(shù)據(jù)有多大這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI