电竞比分网-中国电竞赛事及体育赛事平台

分享

redis 集群(文檔整理)

 頭號(hào)碼甲 2022-03-17

Redis集群

·Redis集群提供了一種運(yùn)行Redis安裝的方法,在該安裝中,數(shù)據(jù)會(huì)在多個(gè)Redis節(jié)點(diǎn)之間自動(dòng)分片。

Redis集群在分區(qū)期間還提供了一定程度的可用性,這實(shí)際上是在某些節(jié)點(diǎn)出現(xiàn)故障或無法通信時(shí)有繼續(xù)工作的能力。但是,如果發(fā)生較嚴(yán)重故障(例如,大多數(shù)主節(jié)點(diǎn)不可用時(shí)),集群將停止運(yùn)行。

實(shí)際上,Redis集群能給你帶來什么?

  • 自動(dòng)在多個(gè)節(jié)點(diǎn)之間拆分?jǐn)?shù)據(jù)集的能力。
  • 當(dāng)一部分節(jié)點(diǎn)出現(xiàn)故障或無法與集群中其他節(jié)點(diǎn)通信時(shí),仍然可以繼續(xù)操作。

Redis集群TCP端口

每個(gè)Redis集群節(jié)點(diǎn)都需要打開兩個(gè)TCP連接。用于服務(wù)客戶端的常規(guī)RedisTCP端口,例如6379,再加上將數(shù)據(jù)端口加10000的端口,比如在示例中為16379。

第二個(gè)值更大一點(diǎn)的端口用于集群總線,也就是使用二進(jìn)制協(xié)議的節(jié)點(diǎn)到節(jié)點(diǎn)之間的通信通道。節(jié)點(diǎn)將集群總線用于故障檢測,配置更新,故障轉(zhuǎn)移授權(quán)等??蛻舳擞肋h(yuǎn)不要嘗試與集群總線端口進(jìn)行通信,而應(yīng)始終與普通的Redis命令端口進(jìn)行通信,但是請(qǐng)確保您在防火墻中同時(shí)打開了這兩個(gè)端口,否則Redis集群節(jié)點(diǎn)將無法進(jìn)行通信。

命令端口和集群總線端口的偏移量是固定的,并且始終為10000。

請(qǐng)注意,對(duì)于每個(gè)節(jié)點(diǎn),要使Redis集群正常工作,您需要:

  1. 用于與客戶端通信的常規(guī)通信端口(通常為6379),向那些需要訪問集群的所有客戶端以及所有其他集群節(jié)點(diǎn)(使用客戶端端口進(jìn)行key遷移)開放。
  2. 集群總線端口(客戶端端口+ 10000)必須可以從所有其他集群節(jié)點(diǎn)訪問。

如果您沒有同時(shí)打開兩個(gè)TCP端口,則集群將無法正常工作。

集群總線使用不同的二進(jìn)制協(xié)議進(jìn)行節(jié)點(diǎn)到節(jié)點(diǎn)的數(shù)據(jù)交換,它更適合于在節(jié)點(diǎn)之間使用較少的帶寬和較少的處理時(shí)間來交換信息。

Redis集群數(shù)據(jù)分片

Redis集群不使用一致性哈希,而是使用一種不同形式的分片,從概念上講每個(gè)key都是我們稱為hash槽的一部分。

Redis集群中有16384個(gè)hash槽,要計(jì)算給定key的hash槽,需將key的CRC16值用16384取模。

Redis集群中的每個(gè)節(jié)點(diǎn)都負(fù)責(zé)hash槽的子集,例如,您可能有一個(gè)包含3個(gè)節(jié)點(diǎn)的集群,其中:

  • 節(jié)點(diǎn)A包含從0到5500的hash槽。
  • 節(jié)點(diǎn)B包含從5501到11000的hash槽。
  • 節(jié)點(diǎn)C包含從11001到16383的hash槽。

這樣可以輕松添加和刪除集群中的節(jié)點(diǎn)。例如,如果我想添加一個(gè)新節(jié)點(diǎn)D,則需要將一些hash槽從節(jié)點(diǎn)A,B,C移到D。類似地,如果我想從集群中刪除節(jié)點(diǎn)A,則只需移動(dòng)A所服務(wù)的hash槽到B和C。當(dāng)節(jié)點(diǎn)A為空時(shí),我可以將其從集群中完全刪除。

因?yàn)閷ash槽從一個(gè)節(jié)點(diǎn)移動(dòng)到另一個(gè)節(jié)點(diǎn)不需要停止操作,所以添加刪除節(jié)點(diǎn)或更改節(jié)點(diǎn)服務(wù)的hash槽的百分比不需要停機(jī)。

只要單個(gè)命令執(zhí)行(或整個(gè)事務(wù)或Lua腳本執(zhí)行)中涉及的所有key都屬于同一個(gè)hash槽,Redis集群就支持多key操作。用戶可以通過使用稱為hash標(biāo)簽的概念來強(qiáng)制多個(gè)key成為同一hash槽的一部分。

hash標(biāo)簽記錄在Redis集群規(guī)范中,注意,如果key的{}中的括號(hào)之間有一個(gè)子字符串,則僅對(duì)字符串中的內(nèi)容進(jìn)行hash處理,例如,一個(gè)叫{foo}的key和另一個(gè)叫{foo} 的 key保證在同一hash槽中,并且可以在以多個(gè)key作為參數(shù)的命令中一起使用。

Redis集群主備模式

為了在主節(jié)點(diǎn)子集發(fā)生故障或無法與大多數(shù)節(jié)點(diǎn)通信時(shí)保持可用,Redis集群使用主備模型,其中每個(gè)hash槽具有從1(主節(jié)點(diǎn)本身)到N個(gè)副本(N -1個(gè)其他備份節(jié)點(diǎn))。

在一個(gè)包含節(jié)點(diǎn)A,B,C的集群中,如果節(jié)點(diǎn)B失敗,則集群將無法繼續(xù),因?yàn)槲覀儾荒転?5501-11000 范圍內(nèi)的hash槽提供服務(wù)。但是,在創(chuàng)建集群(或稍后)時(shí),我們向每個(gè)主節(jié)點(diǎn)添加一個(gè)備份節(jié)點(diǎn),以便最終集群由作為主節(jié)點(diǎn)的A,B,C和作為備份節(jié)點(diǎn)的A1,B1,C1組成 ,如果節(jié)點(diǎn)B發(fā)生故障,系統(tǒng)將能夠持續(xù)運(yùn)行。節(jié)點(diǎn)B1復(fù)制B,并且B發(fā)生故障,集群會(huì)將節(jié)點(diǎn)B1提升為新的主節(jié)點(diǎn),并將繼續(xù)正常運(yùn)行。

但是請(qǐng)注意,如果節(jié)點(diǎn)B和B1同時(shí)失敗,則Redis集群無法繼續(xù)運(yùn)行。

Redis集群的一致性保證

Redis集群無法保證強(qiáng)一致性。 實(shí)際上,這意味著在某些情況下,Redis集群可能會(huì)丟失系統(tǒng)給客戶端的已經(jīng)確認(rèn)的寫操作。

Redis集群可能丟失寫入的第一個(gè)原因是因?yàn)樗褂卯惒綇?fù)制。這意味著在寫入期
間會(huì)發(fā)生以下情況:

  • 您的客戶端向B主節(jié)點(diǎn)寫入數(shù)據(jù)。
  • B主節(jié)點(diǎn)向您的客戶端答復(fù)“確定”。
  • B主節(jié)點(diǎn)將寫操作傳播到其備份節(jié)點(diǎn)B1,B2和B3。

如您所見,B在回復(fù)客戶端之前不會(huì)等待B1,B2,B3的確認(rèn),因?yàn)檫@會(huì)對(duì)Redis造成延遲,因此,如果您的客戶端進(jìn)行了寫操作,然后B會(huì)確認(rèn),但是在它把寫操作發(fā)送給備份節(jié)點(diǎn)之前崩潰了,此時(shí)其中一個(gè)備份節(jié)點(diǎn)(未接收到寫操作)可以升級(jí)為主節(jié)點(diǎn),這樣就永遠(yuǎn)丟失該寫操作。這與配置為每秒將數(shù)據(jù)刷新到磁盤的大多數(shù)數(shù)據(jù)庫所發(fā)生的情況非常相似,因此由于過去使用不涉及分布式系統(tǒng)的傳統(tǒng)數(shù)據(jù)庫系統(tǒng)的經(jīng)驗(yàn),您已經(jīng)可以對(duì)此進(jìn)行合理推斷。同樣,您可以通過強(qiáng)制數(shù)據(jù)庫在答復(fù)客戶端之前刷新磁盤上的數(shù)據(jù)來提高一致性,但這通常會(huì)導(dǎo)致性能過低。在Redis集群下,這相當(dāng)于同步復(fù)制。

基本上,在性能和一致性之間進(jìn)行權(quán)衡是必須的。

Redis集群在需要時(shí)可以通過WAIT命令實(shí)現(xiàn)同步寫,這使得丟失寫的可能性大大降低,但是請(qǐng)注意,即使使用同步復(fù)制,Redis集群也不實(shí)現(xiàn)強(qiáng)一致性:在更復(fù)雜的情況下,總是有可能存在一種場景,就是一個(gè)無法接收數(shù)據(jù)的備份節(jié)點(diǎn)被選為主節(jié)點(diǎn)。

還有一種值得注意的情況,Redis集群也會(huì)丟失寫操作,這種情況發(fā)生在網(wǎng)絡(luò)分區(qū)期間,在該分區(qū)中,客戶端與少數(shù)實(shí)例(至少包括主節(jié)點(diǎn))隔離。

以我們的6個(gè)節(jié)點(diǎn)集群為例,該集群由A,B,C,A1,B1,C1組成,具有3個(gè)主節(jié)點(diǎn)
和3個(gè)備份節(jié)點(diǎn)。還有一個(gè)客戶,我們將其稱為Z1。

發(fā)生分區(qū)后,可能在分區(qū)的一側(cè)有A,C,A1,B1,C1,而在另一側(cè)有B和Z1。

Z1仍然能夠?qū)進(jìn)行寫操作,B將接受其寫入。如果分區(qū)在很短的時(shí)間內(nèi)恢復(fù)正常,則集群將繼續(xù)正常運(yùn)行。但是,如果分區(qū)持續(xù)的時(shí)間足以使B1升級(jí)為該分區(qū)的多數(shù)端的主節(jié)點(diǎn),則Z1向B發(fā)送的寫操作將丟失。

請(qǐng)注意,Z1將能夠發(fā)送到B的寫入量有一個(gè)最大的窗口:如果已經(jīng)有足夠的時(shí)間使大分區(qū)選舉出一個(gè)主節(jié)點(diǎn),則小分區(qū)中的每個(gè)主節(jié)點(diǎn)都將停止接受寫入。該時(shí)間是Redis集群的一個(gè)非常重要的配置指令,稱為節(jié)點(diǎn)超時(shí)。

在節(jié)點(diǎn)超時(shí)之后,主節(jié)點(diǎn)被視為發(fā)生故障,并且可以用其副本之一替換。類似地,在超過指定的時(shí)間后,主節(jié)點(diǎn)還是無法感知大多數(shù)其他主節(jié)點(diǎn),此主節(jié)點(diǎn)進(jìn)入錯(cuò)誤狀態(tài)并停止接受寫入。

Redis集群配置參數(shù)

我們將創(chuàng)建一個(gè)集群部署作為例子。在繼續(xù)之前,讓我們介紹一下Redis集群里的redis.conf文件中引入的配置參數(shù)。
繼續(xù)閱讀下去您就會(huì)獲得更多清晰的要點(diǎn)。

  • cluster-enabled <yes/no> : 如果設(shè)置為yes,Redis實(shí)例中將會(huì)啟用集群支持。否則,該實(shí)例將像往常一樣作為獨(dú)立實(shí)例啟動(dòng)。
  • cluster-config-file : 請(qǐng)注意,盡管有此選項(xiàng),但它是不允許用戶可編輯的配置文件,而是Redis集
    群節(jié)點(diǎn)在每次有變更時(shí)(基本上是狀態(tài))都會(huì)自動(dòng)持久保存的集群配置文件,以便能夠在啟動(dòng)時(shí)重新讀取它。
    該文件列出了諸如集群中其他節(jié)點(diǎn)的內(nèi)容,狀態(tài),持久變量等等之類的東西。通常,在收到某些消息時(shí),此文件將被
    重寫并刷新到磁盤上。
  • cluster-node-timeout <毫秒> :Redis集群節(jié)點(diǎn)在被認(rèn)為故障前的最長間隔時(shí)間。如果無法訪問主節(jié)點(diǎn)的時(shí)間超過指定的時(shí)間長度,則它的備份節(jié)點(diǎn)將對(duì)
    其進(jìn)行故障轉(zhuǎn)移。此參數(shù)也控制Redis集群中的其他重要事情。值得注意的是,在指定的時(shí)間內(nèi)無法連通大多數(shù)主節(jié)點(diǎn)
    的每個(gè)節(jié)點(diǎn)都將停止接受查詢請(qǐng)求。
  • cluster-slave-validity-factor :如果設(shè)置為零,則備份節(jié)點(diǎn)將始終嘗試對(duì)主節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移,而不管主節(jié)點(diǎn)和備份節(jié)點(diǎn)之間的鏈接斷開
    狀態(tài)的時(shí)間長短。如果該值為正,則將最大斷開時(shí)間計(jì)算為節(jié)點(diǎn)超時(shí)時(shí)間乘以此選項(xiàng)提供的因子,如果該節(jié)點(diǎn)是備份
    節(jié)點(diǎn),并且主鏈接斷開的時(shí)間超過了指定的時(shí)間,它將不會(huì)嘗試啟動(dòng)故障轉(zhuǎn)移。例如,如果節(jié)點(diǎn)超時(shí)設(shè)置為5秒,而有
    效性因子設(shè)置為10,則備份節(jié)點(diǎn)與主節(jié)點(diǎn)斷開連接超過50秒將不會(huì)嘗試對(duì)其主節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移。請(qǐng)注意,如果沒有
    備份節(jié)點(diǎn)可以對(duì)其進(jìn)行故障轉(zhuǎn)移,則任何不為零的值都可能導(dǎo)致Redis集群在主節(jié)點(diǎn)發(fā)生故障后不可用。
    在這種情況下,只有當(dāng)原始主節(jié)點(diǎn)重新加入集群后,集群才會(huì)返回可用狀態(tài)。
  • cluster-migration-barrier :主節(jié)點(diǎn)需要保持連接的備份節(jié)點(diǎn)的最小數(shù)量,以便另一個(gè)備份節(jié)點(diǎn)遷移到一個(gè)沒有任何備份節(jié)點(diǎn)覆蓋的主
    節(jié)點(diǎn)。有關(guān)更多信息,請(qǐng)參見本教程中有關(guān)副本遷移的相應(yīng)部分。
  • cluster-require-full-coverage <yes / no>:如果設(shè)置為yes,默認(rèn)情況下,如果某個(gè)節(jié)點(diǎn)未覆蓋一定比例的key空間,集群將停止接受寫入。如果該選項(xiàng)設(shè)
    置為no,即使此節(jié)點(diǎn)僅能處理有關(guān)key的部分子集的請(qǐng)求,集群仍將提供查詢。

創(chuàng)建和使用一個(gè)Redis集群

注意:手動(dòng)部署Redis集群,了解其某些操作非常重要。 但是,如果要盡快建立集群并運(yùn)行,請(qǐng)?zhí)^本節(jié)和下一節(jié),直接轉(zhuǎn)到使用 create-cluster 腳本創(chuàng)建Redis集群。

要?jiǎng)?chuàng)建集群,我們需要做的第一件事就是讓一些空Redis實(shí)例運(yùn)行在集群模式下?;旧?,這意味著不能使用常規(guī)Redis實(shí)例來創(chuàng)建集群,因?yàn)樾枰渲锰厥饽J?,以便Redis實(shí)例啟用集群特定的功能和命令。

以下是最小的Redis集群配置文件:

port 7000  # 端口號(hào)
cluster-enabled yes  # 是成為cluster節(jié)點(diǎn)
cluster-config-file nodes.conf  # 節(jié)點(diǎn)配置文件
cluster-node-timeout 5000   # 節(jié)點(diǎn)超時(shí)時(shí)間
appendonly yes  # 是否使用aof

啟用集群模式的只需要直接打開cluster-enabled命令。每個(gè)實(shí)例還包含該節(jié)點(diǎn)配置存儲(chǔ)位置的文件路徑,默認(rèn)情況下為nodes.conf。 該文件不會(huì)被人接觸。 它只是由Redis集群實(shí)例在啟動(dòng)時(shí)生成,并在需要時(shí)進(jìn)行更新。

請(qǐng)注意,按預(yù)期工作的最小集群要求至少包含三個(gè)主節(jié)點(diǎn)。 對(duì)于您的第一個(gè)測試,強(qiáng)烈建議啟動(dòng)一個(gè)包含三個(gè)主節(jié)點(diǎn)和三個(gè)備份節(jié)點(diǎn)的六個(gè)節(jié)點(diǎn)集群。為此,輸入一個(gè)新目錄并創(chuàng)建以下目錄,該目錄以我們將在給定目錄中運(yùn)行的實(shí)例的端口號(hào)命名。就像是:

mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005

在從7000到7005的每個(gè)目錄中創(chuàng)建一個(gè)redis.conf文件。作為配置文件的模板,只需使用上面的小示例,但請(qǐng)確保根據(jù)目錄名稱用正確的端口號(hào)替換端口號(hào)7000?,F(xiàn)在,將您的redis-server可執(zhí)行文件(從GitHub不穩(wěn)定分支中的最新資源編譯而來)復(fù)制到cluster-test目錄中,最后在您喜歡的終端應(yīng)用程序中打開6個(gè)終端選項(xiàng)卡。

像這樣啟動(dòng)每個(gè)實(shí)例,每個(gè)選項(xiàng)卡一個(gè):

cd 7000
../redis-server ./redis.conf

從每個(gè)實(shí)例的日志中可以看到,由于不存在nodes.conf文件,因此每個(gè)節(jié)點(diǎn)都會(huì)為其分配一個(gè)新的ID。

[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1

該ID將由該實(shí)例永久使用,以使該實(shí)例在集群的上下文中具有唯一的名稱。每個(gè)節(jié)點(diǎn)都使用該ID而不是IP或端口記住其他每個(gè)節(jié)點(diǎn)。 IP地址和端口可能會(huì)更改,但是唯一的節(jié)點(diǎn)標(biāo)識(shí)符在節(jié)點(diǎn)的整個(gè)生命周期中都不會(huì)改變。我們將此標(biāo)識(shí)符簡稱為節(jié)點(diǎn)ID。

創(chuàng)建集群

現(xiàn)在,我們有許多實(shí)例正在運(yùn)行,然后需要通過向節(jié)點(diǎn)寫入一些有意義的配置來創(chuàng)建集群。

如果您使用的是Redis 5,這很容易完成,這是因?yàn)閞edis-cli中嵌入了Redis集群命令行實(shí)用程序,我們可以使用它來創(chuàng)建新集群,檢查或重新分片現(xiàn)有集群等。

對(duì)于Redis版本3或4,有一個(gè)稱為redis-trib.rb的較老的工具,它非常相似。您可以在Redis源代碼分發(fā)的src目錄中找到它。 您需要安裝redis gem才能運(yùn)行redis-trib。

gem install redis

第一個(gè)示例,即集群創(chuàng)建,將在Redis 5中使用redis-cli以及在Redis 3和4中使用redis-trib來顯示。但是,接下來的所有示例都將僅使用redis-cli,因?yàn)槟梢钥吹剿麄冋Z法非常相似,您也可以使用redis-trib.rb help來獲取有關(guān)語法的信息,從而將一個(gè)命令行簡單地更改為另一命令行。 重要:請(qǐng)注意,如果需要,可以對(duì)Redis 4集群使用Redis 5 redis-cli。

要使用redis-cli為Redis 5創(chuàng)建集群,只需鍵入:

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1

對(duì)于redis 4或者3 請(qǐng)使用redis-trib.rb工具:

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

此處使用的命令是create,因?yàn)槲覀円獎(jiǎng)?chuàng)建一個(gè)新集群。 選項(xiàng)
--cluster-replicas 1表示我們希望每個(gè)創(chuàng)建的主節(jié)點(diǎn)都具有一個(gè)備份節(jié)點(diǎn)。其他參數(shù)是要用于創(chuàng)建新集群的實(shí)例
的地址列表。

顯然,滿足我們要求的唯一設(shè)置是創(chuàng)建具有3個(gè)主節(jié)點(diǎn)和3個(gè)從節(jié)點(diǎn)的集群。

Redis-cli將為您提供配置。 鍵入yes,將接受建議的配置。集群將被配置并加入,這意味著實(shí)例將被啟動(dòng)然后彼此
之間可以對(duì)話。 最后,如果一切順利,您將看到如下消息:

[OK] All 16384 slots covered

意思就是說至少有一個(gè)主節(jié)點(diǎn)實(shí)例服務(wù)于16384個(gè)槽位中某一個(gè).

使用create-cluster腳本創(chuàng)建一個(gè)Redis集群

如果您不想如上所述通過手動(dòng)配置和執(zhí)行單個(gè)實(shí)例來創(chuàng)建Redis集群,則可以使用更簡單的系統(tǒng)(但是您將不會(huì)學(xué)到同樣多的操作細(xì)節(jié))。

只需檢查Redis發(fā)行版中的utils / create-cluster目錄。內(nèi)部有一個(gè)名為create-cluster的腳本(名稱與包含在其中的目錄相同),它是一個(gè)簡單的bash腳本。 為了啟動(dòng)具有3個(gè)主節(jié)點(diǎn)和3個(gè)備份節(jié)點(diǎn)的6節(jié)點(diǎn)集群,只需鍵入以下命令:

  1. create-cluster start
  2. create-cluster create

在步驟2中,當(dāng)redis-cli希望您接受集群布局時(shí),回復(fù)yes。

現(xiàn)在,您可以與集群進(jìn)行交互,默認(rèn)情況下,第一個(gè)節(jié)點(diǎn)將從端口30001開始。 完成后,使用以下命令停止集群:

create-cluster stop.

關(guān)于如何運(yùn)行這個(gè)腳本的更多信息,請(qǐng)閱讀目錄里的README。

集群操作

到目前為止,Redis集群的問題之一是缺少客戶端庫的實(shí)現(xiàn)。

據(jù)我所知有以下實(shí)現(xiàn):

  • redis-rb-cluster 是我(@antirez)編寫的Ruby實(shí)現(xiàn),可作為其他語言的參考。它是原始redis-rb的簡單包裝,實(shí)現(xiàn)了最小語義以有效地與集群通信。
  • redis-py-cluster redis-rb-cluster的Python實(shí)現(xiàn)。支持大多數(shù)redis-py功能。正在積極發(fā)展中。
  • 流行的Predis支持Redis集群,該支持最近已更新并且正在積極開發(fā)中。
  • 使用最廣泛的Java客戶端,Jedis最近添加了對(duì)Redis集群的支持,請(qǐng)參閱項(xiàng)目README中的Jedis集群部分。
  • StackExchange.Redis提供對(duì)C#的支持(并且應(yīng)與大多數(shù).NET語言,VB,F(xiàn)#等兼容)
  • thunk-redis提供對(duì)Node.js和io.js的支持,它是基于thunk/promise的redis客戶端,具有管道和集群功能。
    redis-go-cluster是Go語言的
    Redis集群的實(shí)現(xiàn),它使用了Redigo library client作為基本客戶端,通過結(jié)果聚合實(shí)現(xiàn)了MGET/MSET。
  • ioredis是流行的Node.js客戶端,為Redis集群提供了強(qiáng)大的支持。
  • 當(dāng)使用-c開關(guān)啟動(dòng)時(shí),redis-cli程序?qū)崿F(xiàn)了基本的集群支持。

測試Redis集群的一種簡單方法是嘗試上述任何客戶端,或者僅嘗試redis-cli命令。以下是使用后者進(jìn)行交互的示例:

$ redis-cli -c -p 7000
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"

注意:如果使用腳本創(chuàng)建集群,則節(jié)點(diǎn)可能會(huì)偵聽不同的端口,默認(rèn)情況下從30001開始。

redis-cli的支持非?;A(chǔ),因此它始終基于以下事實(shí):Redis集群節(jié)點(diǎn)能夠?qū)⒖蛻舳酥囟ㄏ虻秸_的節(jié)點(diǎn)。一個(gè)嚴(yán)格的客戶端可以做得更好,并且可以在hash槽和節(jié)點(diǎn)地址之間緩存映射,以便直接使用與節(jié)點(diǎn)的正確連接。僅在集群配置中發(fā)生某些更改時(shí)(例如,在故障轉(zhuǎn)移之后或系統(tǒng)管理員通過添加或刪除節(jié)點(diǎn)來更改集群布局之后),才會(huì)刷新映射。

使用redis-rb-cluster寫一個(gè)簡單的應(yīng)用程序

在繼續(xù)展示如何操作Redis集群之前,比如執(zhí)行故障轉(zhuǎn)移或重新分片之類的操作,我們需要?jiǎng)?chuàng)建一些示例應(yīng)用程序,或者至少要能夠理解簡單的Redis集群客戶端交互的語義。

通過這種方式,我們可以運(yùn)行一個(gè)示例,同時(shí)嘗試使節(jié)點(diǎn)發(fā)生故障或開始重新分片,以了解Redis集群在現(xiàn)實(shí)環(huán)境下的行為。只是觀察一個(gè)沒有寫入任何數(shù)據(jù)的集群是沒有幫助的。

本節(jié)說明了redis-rb-cluster的一些基本用法,其中顯示了兩個(gè)示例。 首先是以下內(nèi)容,它是redis-rb-cluster發(fā)行版中的example.rb文件:

 1  require './cluster'
   2
   3  if ARGV.length != 2
   4      startup_nodes = [
   5          {:host => "127.0.0.1", :port => 7000},
   6          {:host => "127.0.0.1", :port => 7001}
   7      ]
   8  else
   9      startup_nodes = [
  10          {:host => ARGV[0], :port => ARGV[1].to_i}
  11      ]
  12  end
  13
  14  rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)
  15
  16  last = false
  17
  18  while not last
  19      begin
  20          last = rc.get("__last__")
  21          last = 0 if !last
  22      rescue => e
  23          puts "error #{e.to_s}"
  24          sleep 1
  25      end
  26  end
  27
  28  ((last.to_i+1)..1000000000).each{|x|
  29      begin
  30          rc.set("foo#{x}",x)
  31          puts rc.get("foo#{x}")
  32          rc.set("__last__",x)
  33      rescue => e
  34          puts "error #{e.to_s}"
  35      end
  36      sleep 0.1
  37  }

該程序做了一件非常簡單的事情,它將foo形式的key的值設(shè)置為數(shù)字,并且是一個(gè)接一個(gè)的遞增。
因此,如果您運(yùn)行該程序,其結(jié)果將和以下命令是一樣的效果:

  • SET foo0 0
  • SET foo1 1
  • SET foo2 2
  • ...

該程序看起來比較復(fù)雜,因?yàn)樗枰谄聊簧巷@示錯(cuò)誤而不是異常退出,因此,對(duì)集群執(zhí)行的每個(gè)操作都應(yīng)該由錯(cuò)誤處理包裝。

第14行是程序中的第一個(gè)有趣的行。它創(chuàng)建Redis集群對(duì)象,使用啟動(dòng)節(jié)點(diǎn)列表作為參數(shù),并允許該對(duì)象與不同節(jié)點(diǎn)建立的最大連接數(shù),最后是超時(shí)時(shí)間,對(duì)于給定的操作多少時(shí)間后被視為失敗。

啟動(dòng)節(jié)點(diǎn)不需要是集群的所有節(jié)點(diǎn)。但至少有一個(gè)節(jié)點(diǎn)是可達(dá)的。還要注意,只要能夠與第一個(gè)節(jié)點(diǎn)連接,redis-rb-cluster就會(huì)更新此啟動(dòng)節(jié)點(diǎn)列表。您應(yīng)該期望任何其他嚴(yán)格的客戶端都應(yīng)該采取這種行為。

現(xiàn)在我們已經(jīng)將Redis集群對(duì)象實(shí)例存儲(chǔ)在rc變量中,我們可以像使用普通的Redis對(duì)象實(shí)例一樣使用該對(duì)象了。

這恰好發(fā)生在第18至26行中:重新啟動(dòng)示例時(shí),我們不想以foo0重新開始,因此我們將計(jì)數(shù)器存儲(chǔ)在Redis本身內(nèi)。上面的代碼旨在讀取此計(jì)數(shù)器,或者如果不存在該計(jì)數(shù)器,則為其分配零值。

但是請(qǐng)注意這是一個(gè)while循環(huán),因?yàn)榧词辜宏P(guān)閉并返回錯(cuò)誤,我們也要一次又一次嘗試。普通的應(yīng)用程序不需要那么小心。

28和37之間開始主循環(huán),在該循環(huán)中設(shè)置key或顯示錯(cuò)誤。

注意循環(huán)結(jié)束時(shí)的sleep調(diào)用。在測試中,如果您想盡可能快地寫入集群,則可以刪除sleep(相對(duì)來說,這只是一個(gè)很繁忙的循環(huán)操作,它并沒有真正的并行,因此,在最好的條件下,您通常將獲得每秒10k個(gè)操作))。

通常,為了使示例程序更容易被人看懂,寫入速度會(huì)減慢。啟動(dòng)應(yīng)用程序?qū)a(chǎn)生以下輸出:

ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C (I stopped the program here)

這不是一個(gè)非常有趣的程序,我們稍后將使用更好的程序,但是我們已經(jīng)可以看到程序運(yùn)行時(shí),在重新分片期間都發(fā)生了什么。

集群重新分片

現(xiàn)在,我們準(zhǔn)備嘗試集群重新分片。 為此,請(qǐng)保持example.rb程序運(yùn)行,以便您查看對(duì)程序的運(yùn)行是否有影響。另外,您可能想注釋一下sleep調(diào)用,以便在重新分片期間發(fā)生一些更嚴(yán)重的寫入負(fù)載。重新分片基本上意味著將hash槽從一組節(jié)點(diǎn)移動(dòng)到另一組節(jié)點(diǎn),并且像集群創(chuàng)建一樣,它使用redis-cli程序完成。

要開始重新分片,只需鍵入:

redis-cli --cluster reshard 127.0.0.1:7000

您只需要指定一個(gè)節(jié)點(diǎn),redis-cli將自動(dòng)找到其他節(jié)點(diǎn)。

當(dāng)前redis-cli僅能在管理員支持下重新分片,您不能僅僅說將5%的插槽從該節(jié)點(diǎn)移到另一個(gè)節(jié)點(diǎn)(當(dāng)然這實(shí)現(xiàn)起來很簡單)。 因此,它會(huì)以一個(gè)問題開始。 首先是您想做多少重分片:

How many slots do you want to move (from 1 to 16384)?

我們可以嘗試重新分派1000個(gè)hash槽,如果該示例仍在運(yùn)行且沒有sleep調(diào)用,則該hash槽應(yīng)已包含少量的key。

然后redis-cli需要知道重新分片的目標(biāo)是什么,也就是將接收hash槽的節(jié)點(diǎn)。 我將使用第一個(gè)主節(jié)點(diǎn),即127.0.0.1:7000,但是我需要指定實(shí)例的節(jié)點(diǎn)ID。redis-cli已將其打印在列表中,但是如果需要的話,我也可以使用以下命令找到節(jié)點(diǎn)的ID:

$ redis-cli -p 7000 cluster nodes | grep myself
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5460

所以我的目標(biāo)節(jié)點(diǎn)應(yīng)該是是 97a3a64667477371c4479320d683e4c8db5858b1。

現(xiàn)在,它會(huì)問你要從哪些節(jié)點(diǎn)獲取這些key。我只輸入all,以便從所有其他主節(jié)點(diǎn)獲取一些hash槽。

最終確認(rèn)后,您會(huì)看到一條消息,表明redis-cli將要從一個(gè)節(jié)點(diǎn)移動(dòng)到另一個(gè)節(jié)點(diǎn),并且將從一側(cè)移動(dòng)到另一側(cè)的每個(gè)實(shí)際的key都會(huì)打印出來。

在重新分片過程中,您應(yīng)該能夠看到示例程序運(yùn)行不受影響。如果需要,您還可以在重新分片期間停止并重新啟動(dòng)它多次。重新分片結(jié)束時(shí),可以使用以下命令測試集群的運(yùn)行狀況:

redis-cli --cluster check 127.0.0.1:7000

所有插槽都會(huì)被覆蓋到,但是這次127.0.0.1:7000的主節(jié)點(diǎn)將具有更多的hash插槽
,大約為6461。

一個(gè)更有趣的示例應(yīng)用程序

我們之前編寫的示例程序不怎么好。它以一種簡單的方式寫入集群,甚至無需檢查寫入的內(nèi)容是否正確。從我們的角度來看,接收寫操作的集群可以始終在每個(gè)操作里將名為foo的key寫到42這個(gè)hash槽里,而我們根本不會(huì)注意到。因此,在redis-rb-cluster代碼倉庫中,有一個(gè)更有趣的程序,稱為consistency-test.rb。它使用一組計(jì)數(shù)器,默認(rèn)為1000,并且發(fā)送INCR命令以增加計(jì)數(shù)器的值。但是,該應(yīng)用程序不僅可以寫數(shù)據(jù),還可以做兩件事:

  • 當(dāng)使用INCR更新計(jì)數(shù)器時(shí),應(yīng)用程序會(huì)記住該寫入。
  • 它還在每次寫入之前讀取一個(gè)隨機(jī)計(jì)數(shù)器,并檢查該值是否符合我們的預(yù)期,并將其與內(nèi)存中的值進(jìn)行比較。

這意味著該程序是一個(gè)簡單的一致性檢查程序,可以告訴您集群是否丟失了一些寫操作,或者它是否接受了我們未收到確認(rèn)的寫操作。在第一種情況下,我們將看到一個(gè)計(jì)數(shù)器的值小于我們之前記住的值,而在第二種情況下,該值將更大。

運(yùn)行一致性測試應(yīng)用程序每秒產(chǎn)生一行輸出:

$ ruby consistency-test.rb
925 R (0 err) | 925 W (0 err) |
5030 R (0 err) | 5030 W (0 err) |
9261 R (0 err) | 9261 W (0 err) |
13517 R (0 err) | 13517 W (0 err) |
17780 R (0 err) | 17780 W (0 err) |
22025 R (0 err) | 22025 W (0 err) |
25818 R (0 err) | 25818 W (0 err) |

該行顯示執(zhí)行的讀取和寫入的次數(shù),以及錯(cuò)誤的數(shù)目(由于系統(tǒng)不可用,因此由于錯(cuò)誤而無法接受查詢)。如果發(fā)現(xiàn)不一致,則將新行添加到輸出中。例如,如果我在程序運(yùn)行時(shí)手動(dòng)重置了計(jì)數(shù)器,就會(huì)發(fā)生這種情況:

$ redis-cli -h 127.0.0.1 -p 7000 set key_217 0
OK

(in the other tab I see...)

94774 R (0 err) | 94774 W (0 err) |
98821 R (0 err) | 98821 W (0 err) |
102886 R (0 err) | 102886 W (0 err) | 114 lost |
107046 R (0 err) | 107046 W (0 err) | 114 lost |

當(dāng)我將計(jì)數(shù)器設(shè)置為0時(shí),實(shí)際值為114,因此程序會(huì)報(bào)告114的寫丟失了(集群無法記住的INCR命令)。該程序作為測試用例更加有趣,因此我們將使用它來測試Redis 集群故障轉(zhuǎn)移。

測試故障轉(zhuǎn)移

注意:在此測試過程中,你應(yīng)打開一個(gè)tab標(biāo)簽頁并在上面運(yùn)行一致性測試應(yīng)用程序。

為了觸發(fā)故障轉(zhuǎn)移,我們可以做的最簡單的事情(也就是在分布式系統(tǒng)中可能發(fā)生的語義上最簡單的失?。┦鞘箚蝹€(gè)進(jìn)程崩潰,在我們的例子中是單個(gè)主機(jī)崩潰。

我們可以使用以下命令來識(shí)別主節(jié)點(diǎn)并使其崩潰:

$ redis-cli -p 7000 cluster nodes | grep master
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385482984082 0 connected 5960-10921
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 master - 0 1385482983582 0 connected 11423-16383
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422

好了,現(xiàn)在7000,7001,7002都是主節(jié)點(diǎn),我們把7002這臺(tái)機(jī)器用DEBUG SEGFAULT命令使其崩潰。

$ redis-cli -p 7002 debug segfault
Error: Server closed the connection

現(xiàn)在我們可以看看這個(gè)一致性測試的輸出的報(bào)告是什么。

18849 R (0 err) | 18849 W (0 err) |
23151 R (0 err) | 23151 W (0 err) |
27302 R (0 err) | 27302 W (0 err) |

... many error warnings here ...

29659 R (578 err) | 29660 W (577 err) |
33749 R (578 err) | 33750 W (577 err) |
37918 R (578 err) | 37919 W (577 err) |
42077 R (578 err) | 42078 W (577 err) |

如您所見,在故障轉(zhuǎn)移期間,系統(tǒng)無法接受578次讀取和577次寫入,但是在數(shù)據(jù)庫中并未創(chuàng)建任何不一致的數(shù)據(jù)。

這聽起來可能是個(gè)意外,因?yàn)樵诒窘坛痰牡谝徊糠种?,我們說過Redis集群在故障轉(zhuǎn)移期間會(huì)丟失寫操作,因?yàn)樗褂卯惒綇?fù)制。我們沒有說的是,這其實(shí)不太可能發(fā)生,因?yàn)镽edis會(huì)給客戶端發(fā)送回應(yīng),并且同樣的命令幾乎同時(shí)會(huì)復(fù)制到備份節(jié)點(diǎn),因此丟失數(shù)據(jù)的窗口很小。但是,很難觸發(fā)這一事實(shí)并不意味著它不可能,因此這不會(huì)改變Redis集群提供的一致性保證。

現(xiàn)在,我們可以檢查故障轉(zhuǎn)移之后的集群設(shè)置是什么(請(qǐng)注意,我重新啟動(dòng)了崩潰的實(shí)例,以便它作為備份節(jié)點(diǎn)重新加入集群):

$ redis-cli -p 7000 cluster nodes
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385503418521 0 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385503419023 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385503419023 3 connected 11423-16383
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385503417005 0 connected 5960-10921
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385503418016 3 connected

現(xiàn)在,主節(jié)點(diǎn)在端口7000、7001和7005上運(yùn)行。以前是主節(jié)點(diǎn)(在端口7002上運(yùn)行的Redis實(shí)例)現(xiàn)在變成了7005的備份節(jié)點(diǎn)。

CLUSTER NODES命令的輸出可能看起來很復(fù)雜,但實(shí)際上非常簡單,由以下標(biāo)記組成:

  • 節(jié)點(diǎn)ID
  • ip:端口
  • 標(biāo)志位: 主節(jié)點(diǎn),備份節(jié)點(diǎn), myself, 失敗狀態(tài), ...
  • 如果自己是備份節(jié)點(diǎn),則是其主節(jié)點(diǎn)的ID
  • 上一次發(fā)出PING后還未收到回復(fù)的持續(xù)時(shí)間.
  • 上一次接收到的PONG的時(shí)間.
  • 節(jié)點(diǎn)的配置epoch (請(qǐng)看 集群規(guī)范).
  • 此節(jié)點(diǎn)的鏈接狀態(tài).
  • 服務(wù)的插槽...

手動(dòng)故障轉(zhuǎn)移

有時(shí),強(qiáng)制進(jìn)行故障轉(zhuǎn)移而實(shí)際上不會(huì)對(duì)主節(jié)點(diǎn)引起任何問題是很有用的。例如,為了升級(jí)主節(jié)點(diǎn)之一的Redis進(jìn)程,最好對(duì)其進(jìn)行故障轉(zhuǎn)移,以將其轉(zhuǎn)變?yōu)閷?duì)可用性的影響最小的備份節(jié)點(diǎn)。

Redis集群使用CLUSTER FAILOVER 命令支持手動(dòng)故障轉(zhuǎn)移,該手動(dòng)故障轉(zhuǎn)移必須在要進(jìn)行故障轉(zhuǎn)移的主節(jié)點(diǎn)的備份節(jié)點(diǎn)之一中執(zhí)行。

與實(shí)際的主服務(wù)器故障導(dǎo)致的故障轉(zhuǎn)移相比,手動(dòng)故障轉(zhuǎn)移是不一樣的,但它更安全,因?yàn)樗鼈冇|發(fā)的方式避免了此過程中的數(shù)據(jù)丟失,只有在系統(tǒng)確定新的主節(jié)點(diǎn)已經(jīng)在運(yùn)行并且替代了舊的主節(jié)點(diǎn)的數(shù)據(jù)復(fù)制功能后,才能將客戶端從原來的主節(jié)點(diǎn)切換到新的主節(jié)點(diǎn)。

在執(zhí)行手動(dòng)故障轉(zhuǎn)移時(shí)在備份節(jié)點(diǎn)日志中可以看到:

# Manual failover user request accepted.
# Received replication offset for paused master manual failover: 347540
# All master replication stream processed, manual failover can start.
# Start of election delayed for 0 milliseconds (rank #0, offset 347540).
# Starting a failover election for epoch 7545.
# Failover election won: I'm the new master.

基本上,連接到我們將要進(jìn)行故障轉(zhuǎn)移的主節(jié)點(diǎn)的客戶端都已停止。同時(shí),主節(jié)點(diǎn)將其復(fù)制偏移發(fā)送到備份節(jié)點(diǎn),備份節(jié)點(diǎn)會(huì)在它這邊等待偏移接收完畢。 當(dāng)復(fù)制偏移量完成時(shí),故障轉(zhuǎn)移開始,并且將向舊的主節(jié)點(diǎn)通知配置切換。 當(dāng)客戶端在舊的主節(jié)點(diǎn)上解鎖時(shí),它們將被重定向到新的主節(jié)點(diǎn)。

添加新節(jié)點(diǎn)

添加新節(jié)點(diǎn)的基本過程是先添加一個(gè)空節(jié)點(diǎn),然后將一些數(shù)據(jù)移入該節(jié)點(diǎn)(如果它是新的主節(jié)點(diǎn)),或者告訴它設(shè)置為已知節(jié)點(diǎn)的副本(如果它是備份節(jié)點(diǎn))。從添加新的主節(jié)點(diǎn)開始,我們兩者都會(huì)展示。在這兩種情況下,要執(zhí)行的第一步都是添加一個(gè)空節(jié)點(diǎn)。這就像在端口7006中啟動(dòng)一個(gè)新節(jié)點(diǎn)(現(xiàn)有的6個(gè)節(jié)點(diǎn)已經(jīng)從7000到7005使用新節(jié)點(diǎn))一樣簡單,除了端口號(hào)之外,其他節(jié)點(diǎn)都使用相同的配置,因此您應(yīng)該按順序進(jìn)行操作以符合我們之前節(jié)點(diǎn)使用的設(shè)置:

  • 在你的終端應(yīng)用上開啟一個(gè)新的tab。
  • 輸入 cluster-test 目錄.
  • 創(chuàng)建一個(gè)名字為7006的文件夾.
  • 在文件夾里創(chuàng)建redis.conf文件, 就跟其他已經(jīng)在使用的節(jié)點(diǎn)一樣,只是換成了7006端口.
  • 最后,通過命令 ../redis-server ./redis.conf 啟動(dòng)服務(wù),

此時(shí)這個(gè)服務(wù)應(yīng)該運(yùn)行起來了?,F(xiàn)在我們可以使用redis-cli來向已有的集群添加一個(gè)節(jié)點(diǎn)。

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

如您所見,我使用add-node命令將新節(jié)點(diǎn)的地址指定為第一個(gè)參數(shù),并將集群中隨機(jī)存在的節(jié)點(diǎn)的地址指定為第二個(gè)參數(shù)。實(shí)際上,redis-cli在這里對(duì)我們沒什么用,它只是向節(jié)點(diǎn)發(fā)送了CLUSTERMEET消息,這也可以手動(dòng)完成。不過redis-cli會(huì)在運(yùn)行之前檢查集群的狀態(tài),因此,即使您知道內(nèi)部結(jié)構(gòu)如何運(yùn)行,通過redis-cli執(zhí)行集群操作是仍然是一個(gè)好主意。

現(xiàn)在,我們可以連接到新節(jié)點(diǎn),以查看它是否確實(shí)加入了集群:

redis 127.0.0.1:7006> cluster nodes
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385543178575 0 connected 5960-10921
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected
f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:7000 master - 0 1385543179080 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385543177568 3 connected 11423-16383

請(qǐng)注意,由于此節(jié)點(diǎn)已經(jīng)連接到集群,因此它已經(jīng)能夠正確重定向客戶端查詢,通常來說它已經(jīng)是集群的一部分了。 但是,與其他主節(jié)點(diǎn)相比,它有兩個(gè)特點(diǎn):

  • 由于沒有分配的hash槽,因此不保存任何數(shù)據(jù)。
  • 因?yàn)樗菦]有分配插槽的主機(jī),所以當(dāng)備份節(jié)點(diǎn)要成為主節(jié)點(diǎn)時(shí),它不會(huì)參與選
    舉過程。

現(xiàn)在可以使用redis-cli的重新分片功能將hash槽分配給該節(jié)點(diǎn)。像上一節(jié)中已經(jīng)展示的那樣,這里我就不展示了,他們的操作沒有區(qū)別,只是將空節(jié)點(diǎn)作為目標(biāo)進(jìn)行重新分片。

添加一個(gè)節(jié)點(diǎn)作為副本(備份節(jié)點(diǎn))

添加一個(gè)備份節(jié)點(diǎn)可以通過2種方式完成。最常用的是用 redis-cli, 不過要用--cluster-slave選項(xiàng),就像這樣:

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave

請(qǐng)注意,此處的命令行與我們用于添加新主節(jié)點(diǎn)的命令行完全相同,因此我們并未指定要向其添加副本的主節(jié)點(diǎn)。在這種情況下,redis-cli要做的就是將新節(jié)點(diǎn)添加給副本較少的主節(jié)點(diǎn)中的隨機(jī)主節(jié)點(diǎn)的副本。但是,您可以使用以下命令行指定想要與新副本一起使用的主節(jié)點(diǎn):

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

這樣我們便將新副本分配給特定的主節(jié)點(diǎn)。

將副本添加到特定主節(jié)點(diǎn)的一種更手動(dòng)的方法是將新節(jié)點(diǎn)添加為空的主節(jié)點(diǎn),然后使用CLUSTER REPLICATE命令將其轉(zhuǎn)換為副本。 如果將該節(jié)點(diǎn)添加為備份節(jié)點(diǎn),但您想將其作為其他主節(jié)點(diǎn)的副本進(jìn)行移動(dòng),也一樣適用。

例如,為了給節(jié)點(diǎn)127.0.0.1:7005添加副本,此節(jié)點(diǎn)當(dāng)前服務(wù)的hash槽正在11423-16383范圍內(nèi),節(jié)點(diǎn)ID為3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,我要做的就是連接到新節(jié)點(diǎn)(已經(jīng)作為空的主節(jié)點(diǎn)添加到集群)并在新節(jié)點(diǎn)上發(fā)送命令:

redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

就是這樣。 現(xiàn)在,這組hash槽有了一個(gè)新副本,并且集群中的所有其他節(jié)點(diǎn)都已經(jīng)知道(幾秒鐘后需要更新其配置)。 我們可以使用以下命令進(jìn)行驗(yàn)證:

$ redis-cli -p 7000 cluster nodes | grep slave | grep 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
f093c80dde814da99c5cf72a7dd01590792b783b 127.0.0.1:7006 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617702 3 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617198 3 connected

節(jié)點(diǎn)3c3a0c...現(xiàn)在有了2個(gè)備份節(jié)點(diǎn),運(yùn)行在7002端口(已存在)和7006端口(新加入的)

移除節(jié)點(diǎn)

為了移除一個(gè)備份節(jié)點(diǎn),只需要在redis-cli上使用del-node 命令:

redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

第一個(gè)參數(shù)只是集群中的一個(gè)隨機(jī)節(jié)點(diǎn),第二個(gè)參數(shù)是您要?jiǎng)h除的節(jié)點(diǎn)的ID。您也可以用相同的方法刪除主節(jié)點(diǎn),但是要?jiǎng)h除主節(jié)點(diǎn),它必須為空。如果主節(jié)點(diǎn)不為空,則需要先將數(shù)據(jù)重新分片到所有其他主節(jié)點(diǎn)。

刪除主節(jié)點(diǎn)的另一種方法是在其一個(gè)備份節(jié)點(diǎn)上對(duì)其執(zhí)行手動(dòng)故障轉(zhuǎn)移,并在該節(jié)點(diǎn)成為新主節(jié)點(diǎn)的備份節(jié)點(diǎn)之后刪除該節(jié)點(diǎn)。顯然,這在您想要減少集群中的主節(jié)點(diǎn)的實(shí)際數(shù)量時(shí)沒什么用,在這種情況下,需要重新分片。

副本遷移

在Redis集群里里任何時(shí)間你都可以重新配置一個(gè)備份節(jié)點(diǎn)使其作為另一個(gè)主節(jié)點(diǎn)的從屬節(jié)點(diǎn),使用下列命令:

CLUSTER REPLICATE <master-node-id>

但是,有一種特殊情況,您希望副本在沒有系統(tǒng)管理員幫助的情況下自動(dòng)從一個(gè)主節(jié)點(diǎn)移動(dòng)到另一個(gè)主節(jié)點(diǎn)。副本的自動(dòng)重新配置稱為副本遷移,它能夠提高Redis集群的可靠性。

注意:您可以在Redis集群規(guī)范中閱讀副本遷移的詳細(xì)信息,這里我們僅提供一些一般的想法以及您應(yīng)該從中受益的信息。

在某些情況下,您可能想讓您的集群副本從一個(gè)主節(jié)點(diǎn)移動(dòng)到另一個(gè)主節(jié)點(diǎn)的原因是,Redis集群通常具有與給定主節(jié)點(diǎn)的副本數(shù)量相同的故障容忍性。

例如,如果一個(gè)主節(jié)點(diǎn)及其副本同時(shí)失敗,則每個(gè)主節(jié)點(diǎn)都有一個(gè)副本的集群將無法繼續(xù)工作,這僅僅是因?yàn)闆]有其他實(shí)例擁有與該主節(jié)點(diǎn)服務(wù)的相同的hash槽的副本。但是,盡管網(wǎng)絡(luò)斷裂可能會(huì)同時(shí)隔離多個(gè)節(jié)點(diǎn),但是許多其他類型的故障(例如單個(gè)節(jié)點(diǎn)本地的硬件或軟件故障)是非常值得注意的一類故障,這類故障不太可能同時(shí)發(fā)生,因此在每個(gè)主節(jié)點(diǎn)都有一個(gè)備份節(jié)點(diǎn)的集群中,如果該備份節(jié)點(diǎn)在凌晨4點(diǎn)被關(guān)閉,而主節(jié)點(diǎn)在凌晨6點(diǎn)被關(guān)閉。這仍然會(huì)導(dǎo)致集群無法運(yùn)行。

為了提高系統(tǒng)的可靠性,我們可以選擇向每個(gè)主節(jié)點(diǎn)添加副本,但這成本很高。副本遷移允許將更多備份節(jié)點(diǎn)添加到少數(shù)幾個(gè)主節(jié)點(diǎn)中。因此,您有10個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)有1個(gè)備份節(jié)點(diǎn),總共20個(gè)實(shí)例。但是,比如您增加了3個(gè)實(shí)例作為某些主節(jié)點(diǎn)的備份節(jié)點(diǎn),因此某些主節(jié)點(diǎn)將具有多個(gè)副本了。

使用副本遷移時(shí),如果一個(gè)主節(jié)點(diǎn)不包含備份節(jié)點(diǎn),則具有多個(gè)備份節(jié)點(diǎn)的主節(jié)點(diǎn)的副本將遷移到孤立的主節(jié)點(diǎn)。因此,當(dāng)您的備份節(jié)點(diǎn)在上述示例中的凌晨4點(diǎn)關(guān)閉之后,另一個(gè)備份節(jié)點(diǎn)將接替它;當(dāng)主節(jié)點(diǎn)在凌晨5點(diǎn)也發(fā)生故障時(shí),另一個(gè)備份節(jié)點(diǎn)將被選舉成為主節(jié)點(diǎn),以便集群可以繼續(xù)操作。

所以您應(yīng)該了解哪些有關(guān)副本遷移的知識(shí)?

  • 在某個(gè)時(shí)刻,集群會(huì)嘗試從具有最多副本數(shù)的主節(jié)點(diǎn)中選擇一個(gè)副本進(jìn)行遷移。
  • 為了從副本遷移中受益,您只需為集群中的單個(gè)主節(jié)點(diǎn)添加一些副本,不管是哪個(gè)主節(jié)點(diǎn)
  • 有一個(gè)配置參數(shù)可控制副本遷移功能,稱為cluster-migration-barrier:您可
    以在Redis集群隨附的示例redis.conf文件中了解有關(guān)此功能的更多信息。
    參考

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多