Redis Cluster提供了一種運行Redis安裝的方法,其中數據 在多個Redis節點之間自動分片。java
Redis Cluster還在分區期間提供必定程度的可用性,其實是在某些節點發生故障或沒法通訊時繼續運行的能力。可是,若是發生較大的故障(例如,當大多數主設備不可用時),集羣將中止運行。node
因此實際上,你對Redis Cluster有什麼見解?git
每一個Redis集羣節點都須要打開兩個TCP鏈接。用於爲客戶端提供服務的普通Redis TCP端口,例如6379,加上經過向數據端口添加10000得到的端口,所以示例中爲16379。github
第二個端口用於集羣總線,即便用二進制協議的節點到節點的通訊通道。節點使用集羣總線進行故障檢測,配置更新,故障轉移受權等。客戶端永遠不該嘗試與集羣總線端口通訊,但始終使用正常的Redis命令端口,但請確保在防火牆中打開兩個端口,不然Redis集羣節點將沒法通訊。redis
命令端口和集羣總線端口偏移是固定的,始終爲10000。docker
請注意,對於每一個節點,要使Redis集羣正常工做,您須要:數據庫
若是不打開兩個TCP端口,則集羣將沒法按預期工做。promise
集羣總線使用不一樣的二進制協議進行節點到節點的數據交換,這更適合於使用不多的帶寬和處理時間在節點之間交換信息。緩存
目前,Redis集羣不支持NATted環境,也不支持從新映射IP地址或TCP端口的通常環境。安全
Docker使用一種稱爲端口映射的技術:與程序使用的端口相比,在Docker容器內運行的程序可能會使用不一樣的端口。這對於在同一服務器中同時使用相同端口運行多個容器很是有用。
爲了使Docker與Redis Cluster兼容,您須要使用Docker 的主機網絡模式。有關更多信息,請查看Docker文檔中的--net=host
選項。
Redis Cluster不使用一致的散列,而是使用不一樣形式的分片,其中每一個鍵在概念上都是咱們稱之爲散列槽的一部分。
Redis集羣中有16384個散列槽,爲了計算給定key的散列槽,咱們只需採用key模數爲16384的CRC16。
Redis集羣中的每一個節點都負責哈希槽的子集,例如,您可能擁有一個包含3個節點的集羣,其中:
這容許輕鬆添加和刪除集羣中的節點。例如,若是我想添加一個新節點D,我須要將一些哈希槽從節點A,B,C移動到D。一樣,若是我想從集羣中刪除節點A,我只需移動A服務的哈希槽到B和C。當節點A爲空時,我能夠徹底從集羣中刪除它。
由於將哈希槽從一個節點移動到另外一個節點不須要中止操做,添加和刪除節點,或者更改節點所持有的哈希槽的百分比,因此不須要任何停機時間。
只要涉及單個命令執行(或整個事務或Lua腳本執行)的全部鍵都屬於同一個哈希槽,Redis Cluster就支持多個鍵操做。用戶能夠經過使用稱爲哈希標記的概念強制多個key成爲同一哈希槽的一部分。
Hash標籤記錄在Redis集羣規範中,但要點是若是key中{}括號之間有子字符串,則只對字符串內部的內容進行哈希處理,例如,保證this{foo}key
與another{foo}key
位於相同的哈希槽中,可使多個鍵在一個參數的命令中一塊兒使用。
爲了在主節點子集發生故障或沒法與大多數節點通訊時保持可用,Redis Cluster使用主從模型,其中每一個散列槽從1(主機自己)到N個副本(N-1個額外的從節點)。
在具備節點A,B,C的示例集羣中,若是節點B發生故障,則集羣沒法繼續,由於咱們再也不可以在5501-11000範圍內提供服務哈希位置的方法。
然而,當建立集羣時(或稍後),咱們向每一個主節點添加一個從節點,以便最終集羣由做爲主節點的A,B,C和做爲從節點的A1,B1,C1組成。 ,若是節點B出現故障,系統就能繼續運行。
節點B1複製B,B失敗,集羣將節點B1升級爲新的主節點,並將繼續正常運行。
但請注意,若是節點B和B1同時發生故障,Redis Cluster將沒法繼續運行。
Redis Cluster沒法保證強一致性。實際上,這意味着在某些條件下,Redis Cluster可能會丟失系統向客戶端確認的寫入。
Redis Cluster可能丟失寫入的第一個緣由是它使用異步複製。這意味着在寫入期間會發生如下狀況:
正如你所看到的,B在回覆客戶端以前並無等待來自B1,B2,B3的確認,由於這對Redis來講是一個太高的延遲懲罰,因此若是你的客戶端寫了一些內容,B會確認寫入,可是崩潰在寫入發送到其從屬以前,其中一個從屬(沒有接收到寫入)能夠提高爲master,將會永遠丟失寫入。
這與配置爲每秒將數據刷新到磁盤的大多數數據庫所發生的狀況很是類似,所以,因爲過去使用不涉及分佈式系統的傳統數據庫系統的經驗,所以您已經可以推斷這種狀況。一樣,您能夠經過在回覆客戶端以前強制數據庫刷新磁盤上的數據來提升一致性,但這一般會致使性能太低。在Redis Cluster的狀況下,這至關於同步複製。
基本上須要在性能和一致性之間進行權衡。
Redis Cluster在絕對須要時支持同步寫入,經過WAIT命令實現,這使得丟失寫入的可能性大大下降,但請注意,即便使用同步複製,Redis Cluster也不會實現強一致性:在更復雜的狀況下老是能夠實現失敗場景,沒法接收寫入的slave被選爲master。
還有另外一個值得注意的狀況是,Redis集羣將丟失寫入,這種狀況發生在網絡分區中,其中客戶端與少數實例(至少包括主服務器)隔離。
以6個節點簇爲例,包括A,B,C,A1,B1,C1,3個master和3個slave。還有一個客戶,咱們稱之爲Z1。
在發生分區以後,可能在分區的一側有A,C,A1,B1,C1,在另外一側有B和Z1。
Z1仍然能夠寫入B,它將接受其寫入。若是分區在很短的時間內恢復,集羣將繼續正常運行。可是,若是分區持續足夠的時間使B1在分區的多數側被提高爲主,則Z1發送給B的寫入將丟失。
請注意,Z1將可以發送到B的寫入量存在最大窗口:若是分區的多數方面已經有足夠的時間將從屬設備選爲主設備,則少數端的每一個主節點都會中止接受寫入。
這段時間是Redis Cluster的一個很是重要的配置指令,稱爲節點超時。
節點超時事後,主節點被視爲失敗,能夠由其中一個副本替換。相似地,在節點超時已通過去而主節點沒法感知大多數其餘主節點以後,它進入錯誤狀態並中止接受寫入。
咱們即將建立一個示例集羣部署。在繼續以前,讓咱們介紹Redis Cluster在redis.conf
文件中引入的配置參數。有些會很明顯,有些會在你繼續閱讀時更清楚。
注意:要手動部署Redis集羣**,瞭解它的某些操做方面很是重要**。可是,若是要啓動集羣並儘快運行,請跳過本節和下一節,而後直接使用create-cluster腳本建立Redis集羣。
要建立集羣,咱們首先要作的是在集羣模式下運行一些空的Redis實例。這基本上意味着不使用普通Redis實例建立集羣,由於須要配置特殊模式,以便Redis實例啓用集羣特定功能和命令。
如下是最小的Redis集羣配置文件:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
複製代碼
正如您所看到的,啓用集羣模式的只是cluster-enabled
指令。每一個實例還包含存儲此節點配置的文件路徑,默認狀況下爲nodes.conf
。這個文件永遠不會被人類接觸;它只是在Redis Cluster實例啓動時生成,並在每次須要時更新。copy的時候,記得修改nodes.conf
的名字,如nodes-7001.conf
。
請注意,按預期工做的最小集羣須要包含至少三個主節點。對於您的第一次測試,強烈建議啓動具備三個主設備和三個從設備的六節點集羣。
爲此,請輸入一個新目錄,並建立以咱們將在任何給定目錄中運行的實例的端口號命名的如下目錄。
就像是:
mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005
複製代碼
redis.conf
在每一個目錄中建立一個文件,從7000到7005做爲配置文件的模板,只需使用上面的小例子,但請確保根據目錄名稱用正確的端口號替換端口號7000
。
如今將從GitHub的unstable分支中的最新源編譯的 redis-server可執行文件複製到cluster-test
目錄中,最後在您喜歡的終端應用程序中打開6個終端tabs。
像這樣開始每一個實例,每一個tab一個:
cd 7000
../redis-server ./redis.conf
複製代碼
從每一個實例的日誌中能夠看出,因爲不存在任何nodes.conf
文件,所以每一個節點都會爲本身分配一個新ID。
[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1 複製代碼
此特定實例將永久使用此ID,以使實例在集羣的上下文中具備惟一名稱。每一個節點都使用此ID記住每一個其餘節點,而不是經過IP或端口記住。IP地址和端口可能會發生變化,但惟一的節點標識符永遠不會在節點的整個生命週期內發生變化。咱們稱這個標識符爲Node ID。
如今咱們已經運行了許多實例,咱們須要經過向節點編寫一些有意義的配置來建立咱們的集羣。
若是您使用的是Redis 5,這很容易實現,由於咱們在嵌入的Redis Cluster命令行實用程序redis-cli
的幫助下,可用於建立新集羣,檢查或從新塑形現有集羣等等。
對於Redis版本3或4,有一個名爲redis-trib.rb
很是類似的舊工具。您能夠src
在Redis源代碼分發的目錄中找到它。你須要安裝redis
gem才能運行redis-trib
。
gem install redis
複製代碼
第一個例子,即集羣建立,將在Redis 5的redis-cli
和Redis 3和4中的redis-trib
同時顯示。可是全部下面的例子都只會使用redis-cli
,由於你能夠看到語法很是類似,你能夠經過使用redis-trib.rb help
獲取有關舊語法的信息將一個命令行更改成另外一個命令行。**重要提示:**請注意,若是您願意,可使用Redis 5 的redis-cli
代替Redis 4集羣。
要爲Redis 5建立集羣,redis-cli
只需鍵入(若是redis有密碼記得加入-a參數,要遠程調用請配置公網ip):
redis-cli -a 123456 --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
複製代碼
使用redis-trib.rb
用於Redis的4或3:
./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,由於咱們想要建立一個新的集羣。該選項--cluster-replicas 1
意味着咱們但願每一個建立的主服務器都有一個從服 其餘參數是我要用於建立新集羣的實例的地址列表。
顯然,咱們要求的惟一設置是建立一個包含3個主服務器和3個從服務器的集羣。
Redis-cli將爲您提供配置。鍵入yes接受建議的配置。將配置並加入集羣,這意味着實例將被引導爲彼此通訊。最後,若是一切順利,你會看到這樣的消息:
[OK] All 16384 slots covered
這意味着至少有一個主實例爲16384個可用插槽提供服務。
若是您不想經過如上所述手動配置和執行單個實例來建立Redis集羣,則可使用更簡單的系統(但您不會學習相同數量的操做詳細信息)。
只需檢查Redis發行版中的utils/create-cluster
目錄便可。create-cluster
內部有一個腳本(與其包含的目錄同名),它是一個簡單的bash腳本。要啓動具備3個主服務器和3個從服務器的6節點集羣,只需鍵入如下命令:
一、create-cluster start
二、create-cluster create
yes
當redis-cli
實用程序但願您接受集羣佈局時,在步驟2中回覆。
您如今能夠與集羣交互,默認狀況下,第一個節點將從端口30001開始。完成後,使用如下命令中止集羣:
一、create-cluster stop
。
README
有關如何運行腳本的更多信息,請閱讀此目錄中的內容。
在此階段,Redis Cluster的一個問題是缺乏客戶端庫實現。
我知道如下實現:
redis-cli
工具實現了一個很是基本的集羣支持-c
開關。測試Redis Cluster的一種簡單方法是嘗試上述任何客戶端或僅使用redis-cli
命令行實用程序。如下是使用後者的交互示例:
$ 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"
複製代碼
**注意:**若是使用腳本建立集羣,則節點能夠偵聽不一樣的端口,默認狀況下從30001開始。
redis-cli集羣支持很是基礎,所以它老是使用Redis集羣節點可以將客戶端重定向到右節點的事實。一個認真的客戶端可以作得更好,並在哈希槽和節點地址之間緩存地圖,以直接使用與正確節點的正確鏈接。僅當集羣配置中的某些內容發生更改時(例如,在故障轉移以後或系統管理員經過添加或刪除節點更改集羣佈局後),纔會刷新映射。
在繼續展現如何操做Redis集羣,執行故障轉移或從新分片以前,咱們須要建立一些示例應用程序,或者至少可以理解簡單的Redis集羣客戶端交互的語義。
經過這種方式,咱們能夠運行一個示例,同時嘗試使節點失敗,或者開始從新分片,以瞭解Redis Cluster在真實條件下的行爲方式。觀察集羣時沒有數據寫入並非頗有幫助。
本節介紹了redis-rb-cluster的一些基本用法, 展現了兩個示例。第一個是如下內容,是redis-rb-cluster發行版中的文件 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<number>
一個接一個設置爲number
。所以,若是您運行該程序,結果是如下命令流:
該程序看起來比它應該更復雜,由於它被設計爲在屏幕上顯示錯誤而不是以異常退出,所以使用集羣執行的每一個操做都由begin
rescue
塊包裝。
第14行是該程序中第一個有趣的行。它建立Redis Cluster對象,使用startup nodes list做爲參數,容許此對象對不一樣節點採用不一樣的最大鏈接數,最後在給定timeout,被認爲給定的失敗操做。
不須要集羣的全部節點都啓動。重要的是至少有一個節點是可達的。另請注意,只要redis-rb-cluster可以與第一個節點鏈接,它就會更新此啓動節點列表。您應該指望與任何其餘嚴肅的客戶端都有這樣的行爲。
既然咱們已將Redis Cluster對象實例存儲在rc變量中,咱們就可使用該對象,就好像它是一個普通的Redis對象實例同樣。
這正是第18到26行所發生的事情:當咱們從新啓動示例時,咱們不想再次啓動foo0
,所以咱們將計數器存儲在Redis自己中。上面的代碼用於讀取此計數器,或者若是計數器不存在,則將其賦值爲零。
但請注意它是如何循環,由於咱們想要反覆嘗試,即便集羣已關閉並返回錯誤。普通應用程序不須要那麼當心。
28到37之間的行啓動主循環,其中設置了鍵或顯示錯誤。
注意sleep
循環結束時的調用。在你的測試中,若是你想盡量快地寫入集羣,你能夠刪除sleep(相對於這是一個繁忙的循環,固然沒有真正的並行性,因此在最好的條件下,你一般會獲得10k的操做/秒)。
一般,寫入速度會下降,以便示例應用程序更容易被人類遵循。
啓動應用程序會生成如下輸出:
ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C (I stopped the program here)
複製代碼
這不是一個很是有趣的程序,咱們稍後會使用更好的程序,但咱們已經能夠看到程序運行時從新分片期間會發生什麼。
如今咱們準備嘗試集羣從新分片了。爲此,請保持example.rb程序運行,以便您能夠查看是否對運行的程序有一些影響。此外,您可能想要繼續執行該sleep
調用,以防止在從新分片期間有一些更嚴重的寫入負載。
從新分片基本上意味着將散列槽從一組節點移動到另外一組節點,而且像集羣建立同樣,它是使用redis-cli實用程序完成的。
要開始從新分片,只需輸入:
redis-cli --cluster reshard 127.0.0.1:7000
您只需指定一個節點,redis-cli將自動找到其餘節點。
目前redis-cli只能經過管理員支持從新加載,你不能只說將5%的插槽從這個節點移動到另外一個節點(但這實現起來很是簡單)。因此它從問題開始。首先是你要作多少大的從新分數:
How many slots do you want to move (from 1 to 16384)?
咱們能夠嘗試從新設置1000個散列槽,若是示例在沒有調用sleep的狀況下運行,那麼該散列槽應該包含很是少許的key。
而後redis-cli須要知道從新分片的目標是什麼,即接收哈希槽的節點。我將使用第一個主節點,即127.0.0.1:7000,但我須要指定實例的節點ID。這已由redis-cli打印在列表中,但若是須要,我總能使用如下命令找到節點的ID:
$ redis-cli -p 7000 cluster nodes | grep myself
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5460
複製代碼
好的,個人目標節點是97a3a64667477371c4479320d683e4c8db5858b1。
如今,您將被問到要從哪些節點獲取這些key。我只是輸入all
以便從全部其餘主節點獲取一些哈希槽。
在最終確認以後,您將看到redis-cli將從一個節點移動到另外一個節點的每一個插槽的消息,而且將爲從一側移動到另外一側的每一個實際鍵打印一個點。
從新分片正在進行中時,您應該可以看到您的示例程序不受影響地運行。若是須要,您能夠在從新分片期間屢次中止並從新啓動它。
在從新分片結束時,您可使用如下命令測試集羣的運行情況:
redis-cli --cluster check 127.0.0.1:7000
全部的插槽都會像往常同樣被覆蓋,但此次127.0.0.1:7000的主機將有更多的散列槽,大約6461。
能夠自動執行從新分片,而無需以交互方式手動輸入參數。這可使用以下命令行:
redis-cli reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
複製代碼
若是您可能常常從新設置,則容許構建一些自動操做,可是目前沒法redis-cli
自動從新平衡集羣,檢查跨集羣節點的key分發以及根據須要智能地移動插槽。此功能將在將來添加。
有時強制進行故障轉移而不會在主服務器上形成任何問題。例如,爲了升級其中一個主節點的Redis進程,最好對其進行故障轉移,以便將其轉換爲從屬,對可用性的影響最小。
Redis Cluster使用CLUSTER FAILOVER 命令支持手動故障轉移,該命令必須在要故障轉移的master的一個slave中執行。
手動故障轉移是特殊的,與實際主故障致使的故障轉移相比更安全,由於它們以免數據丟失的方式發生,經過僅在系統肯定新的主服務器時將客戶端從原始主服務器切換到新主服務器master處理了舊的複製流。
這是您在執行手動故障轉移時在從屬日誌中看到的內容:
# 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.
複製代碼
基本上鍊接到咱們正在故障的主服務器的客戶端被中止。同時主設備將其複製偏移量發送給從設備,該設備等待到達其側面的偏移量。達到複製偏移量時,將啓動故障轉移,並通知舊主服務器有關配置開關的信息。在舊主服務器上取消阻止客戶端時,會將它們重定向到新主服務器。
添加新節點基本上是添加空節點而後將一些數據移入其中(若是它是新主節點)或者告訴它設置爲已知節點的副本(若是它是從屬節點)的過程。
咱們將展現二者,從添加新的主實例開始。
在這兩種狀況下,執行的第一步是添加空節點。
這很簡單,只須要在端口7006中啓動一個新節點(咱們已經在7000到7005之間使用現有的6個節點),其餘節點使用相同的配置,端口號除外,因此你應該按順序作什麼符合咱們用於之前節點的設置:
cluster-test
目錄。7006
。../redis-server ./redis.conf
此時服務器應該正在運行。
如今咱們能夠像往常同樣使用redis-cli,以便將節點添加到現有集羣中。
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
複製代碼
如您所見,我使用add-node命令將新節點的地址指定爲第一個參數,並將集羣中隨機存在節點的地址指定爲第二個參數。
實際上,redis-cli在這方面作的不多幫助咱們,它只是向節點發送了一個CLUSTER MEET消息,這也能夠手動完成。可是redis-cli在運行以前也會檢查集羣的狀態,因此即便你知道內部是如何工做的,經過redis-cli執行集羣操做是個好主意。
如今咱們能夠鏈接到新節點以查看它是否真正加入了集羣:
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
複製代碼
請注意,因爲此節點已鏈接到集羣,所以它已可以正確地重定向客戶端查詢,而且一般是集羣的一部分。然而,與其餘master相比,它有兩個特色:
如今可使用resharding功能爲此節點分配哈希槽redis-cli
。就像咱們在上一節中所作的那樣,它只是將一個空節點從新分區的過程。
添加新副本能夠經過兩種方式執行。顯而易見的是再次使用redis-cli,使用--cluster-slave選項,以下所示:
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave
複製代碼
請注意,此處的命令行與咱們用於添加新主服務器的命令行徹底相同,所以咱們不指定要添加副本的主服務器。在這種狀況下,會發生的事情是redis-cli會將新節點做爲隨機主副本的副本添加到副本較少的主服務器中。
可是,您可使用如下命令行準確指定要使用新副本定位的主控制器:
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
複製代碼
這樣咱們就能夠將新副本分配給特定的主副本。
將副本添加到特定主節點的更手動方法是將新節點添加爲空主節點,而後使用CLUSTER REPLICATE命令將其轉換爲副本 。若是將節點添加爲從屬節點但您想將其做爲不一樣主節點的副本移動,則此方法也有效。
例如,爲了添加當前服務於11423-16383範圍內的哈希槽的節點127.0.0.1:7005的副本,其具備節點ID3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,我須要作的就是鏈接新節點(已經添加爲空主)併發送命令:
redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
複製代碼
而已。如今咱們爲這組哈希槽提供了一個新的副本,而且集羣中的全部其餘節點都已知道(須要幾秒鐘後才能更新它們的配置)。咱們可使用如下命令進行驗證:
$ 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
複製代碼
節點3c3a0c ...如今具備兩個從設備,在端口7002(現有的一個)和7006(新的一個)上運行。
要刪除從節點,只需使用redis-cli命令del-node
:
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`
複製代碼
第一個參數只是集羣中的隨機節點,第二個參數是要刪除的節點的ID。
您也能夠以相同的方式刪除主節點,可是爲了刪除主節點,它必須爲空。若是主服務器不爲空,則須要將數據從其從新分配給全部其餘主節點。
刪除主節點的另外一種方法是在其中一個從節點上執行手動故障轉移,並在節點變爲新主節點的從節點後將其刪除。顯然,當你想減小集羣中實際的主數量時,這沒有用,在這種狀況下,須要從新分片。
在Redis集羣中,只需使用如下命令,就能夠隨時使用不一樣的主服務器從新配置從屬服務器進行復制:
CLUSTER REPLICATE <master-node-id>
複製代碼
可是,有一種特殊狀況,您但願副本在沒有系統管理員幫助的狀況下自動從一個主服務器移動到另外一個主服務器。副本的自動從新配置稱爲副本遷移,而且可以提升Redis集羣的可靠性。
注意:您能夠在Redis集羣規範中閱讀副本遷移的詳細信息,這裏咱們僅提供有關通常概念的一些信息以及您應該從中獲益的信息。
您可能但願讓集羣副本在特定條件下從一個主服務器移動到另外一個主服務器的緣由是,一般Redis集羣與附加到給定主服務器的副本數量同樣能夠抵禦故障。
例如,若是主服務器及其副本同時發生故障,則每一個主服務器具備單個副本的集羣沒法繼續操做,緣由很簡單,由於沒有其餘實例能夠擁有主服務器所服務的散列插槽的副本。然而,雖然netsplits可能同時隔離多個節點,但許多其餘類型的故障(如單個節點本地的硬件或軟件故障)是一類很是值得注意的故障,不太可能同時發生,因此有可能在你的集羣中每一個master都有一個slave,slave在凌晨4點被殺死,master在早上6點被殺死。這仍然會致使集羣沒法再運行。
爲了提升系統的可靠性,咱們能夠選擇爲每一個master添加額外的副本,但這很昂貴。副本遷移容許向少數主服務器添加更多從服務器。因此你有10個master,每一個master有1個slave,總共20個實例。可是,例如,您添加了3個實例做爲某些主服務器的從屬服務器,所以某些主服務器將擁有多個服務器。
對於副本遷移,發生的狀況是,若是master沒有slave,則來自具備多個slave的master的副本將遷移到孤立master。因此在咱們上面的例子中你的slave凌晨4點關閉以後,另外一個slave將佔據它的位置,當master在凌晨5點失敗時,仍然有一個slave能夠被選舉,以便集羣能夠繼續操做。
那麼您應該簡要了解副本遷移的內容?
cluster-migration-barrier
:您能夠在redis.conf
Redis Cluster提供的示例文件中閱讀有關它的更多信息。package com.lamarsan.cluster;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* className: Test
* description: TODO
*
* @author hasee
* @version 1.0
* @date 2019/9/16 20:31
*/
public class Test {
public static void main(String[] args) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大鏈接數
poolConfig.setMaxTotal(1);
// 最大空閒數
poolConfig.setMaxIdle(1);
// 最大容許等待時間,若是超過這個時間還未獲取到鏈接,則會報JedisException異常:
// Could not get a resource from the pool
poolConfig.setMaxWaitMillis(1000);
Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();
nodes.add(new HostAndPort("******", 7000));
nodes.add(new HostAndPort("******", 7001));
nodes.add(new HostAndPort("******", 7002));
nodes.add(new HostAndPort("******", 7003));
nodes.add(new HostAndPort("******", 7004));
nodes.add(new HostAndPort("******", 7005));
String password = "******";
JedisCluster cluster = new JedisCluster(nodes, 10000, 1000, 1000, password, poolConfig);
cluster.setnx("foo","bar");
System.out.println(cluster.get("foo"));
try {
cluster.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
複製代碼