redis集群

redis集群分為服務端集群和客戶端分片腺办,redis3.0以上版本實現了集群機制腕扶,即服務端集群,3.0以下使用客戶端分片(Sharding)雌续。redis3.0服務端集群使用哈希槽斩个,計算key的CRC16結果再模16834。3.0以下版本采用Key的一致性hash算法來區(qū)分key存儲在哪個Redis實例上西雀。

JedisPoolConfig config=newJedisPoolConfig();

config.setMaxTotal(500);

config.setTestOnBorrow(true);

List(2);

jdsInfoList.add(newJedisShardInfo("192.168.2.128",6379));

jdsInfoList.add(newJedisShardInfo("192.168.2.108",6379));

pool =newShardedJedisPool(config, jdsInfoList, Hashing.MURMUR_HASH,Sharded.DEFAULT_KEY_TAG_PATTERN);


---------------------

作者:Rosanu

來源:CSDN

原文:https://blog.csdn.net/rosanu_blog/article/details/68066756?utm_source=copy

版權聲明:本文為博主原創(chuàng)文章萨驶,轉載請附上博文鏈接歉摧!

Redis 集群教程

本文檔是Redis集群的一般介紹艇肴,沒有涉及復雜難懂的分布式概念的贅述,只是提供了從用戶角度來如何搭建測試以及使用的方法叁温,如果你打算使用并深入了解Redis集群再悼,推薦閱讀完本章節(jié)后,仔細閱讀?Redis 集群規(guī)范?一章。

本教程試圖提供最終用戶一個簡單的關于集群和一致性特征的描述

請注意膝但,本教程使用于Redis3.0(包括3.0)以上版本

如果你計劃部署集群冲九,那么我們建議你從閱讀這個文檔開始。

Redis集群介紹

Redis 集群是一個提供在多個Redis間節(jié)點間共享數據的程序集跟束。

Redis集群并不支持處理多個keys的命令,因為這需要在不同的節(jié)點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤.

Redis 集群通過分區(qū)來提供一定程度的可用性,在實際環(huán)境中當某個節(jié)點宕機或者不可達的情況下繼續(xù)處理命令. Redis 集群的優(yōu)勢:

自動分割數據到不同的節(jié)點上莺奸。

整個集群的部分節(jié)點失敗或者不可達的情況下能夠繼續(xù)處理命令。

Redis 集群的數據分片

Redis 集群沒有使用一致性hash, 而是引入了?哈希槽的概念.

Redis 集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽.集群的每個節(jié)點負責一部分hash槽,舉個例子,比如當前集群有3個節(jié)點,那么:

節(jié)點 A 包含 0 到 5500號哈希槽.

節(jié)點 B 包含5501 到 11000 號哈希槽.

節(jié)點 C 包含11001 到 16384號哈希槽.


這種結構很容易添加或者刪除節(jié)點. 比如如果我想新添加個節(jié)點D, 我需要從節(jié)點 A, B, C中得部分槽到D上. 如果我想移除節(jié)點A,需要將A中的槽移到B和C節(jié)點上,然后將沒有任何槽的A節(jié)點從集群中移除即可. 由于從一個節(jié)點將哈希槽移動到另一個節(jié)點并不會停止服務,所以無論添加刪除或者改變某個節(jié)點的哈希槽的數量都不會造成集群不可用的狀態(tài).


Redis 集群的主從復制模型

為了使在部分節(jié)點失敗或者大部分節(jié)點無法通信的情況下集群仍然可用冀宴,所以集群使用了主從復制模型,每個節(jié)點都會有N-1個復制品.

在我們例子中具有A灭贷,B,C三個節(jié)點的集群,在沒有復制模型的情況下,如果節(jié)點B失敗了略贮,那么整個集群就會以為缺少5501-11000這個范圍的槽而不可用.

然而如果在集群創(chuàng)建的時候(或者過一段時間)我們?yōu)槊總€節(jié)點添加一個從節(jié)點A1甚疟,B1,C1,那么整個集群便有三個master節(jié)點和三個slave節(jié)點組成逃延,這樣在節(jié)點B失敗后览妖,集群便會選舉B1為新的主節(jié)點繼續(xù)服務,整個集群便不會因為槽找不到而不可用了

不過當B和B1 都失敗后揽祥,集群是不可用的.

Redis 一致性保證

Redis 并不能保證數據的強一致性. 這意味這在實際中集群在特定的條件下可能會丟失寫操作.

第一個原因是因為集群是用了異步復制. 寫操作過程:

客戶端向主節(jié)點B寫入一條命令.

主節(jié)點B向客戶端回復命令狀態(tài).

主節(jié)點將寫操作復制給他得從節(jié)點 B1, B2 和 B3.

主節(jié)點對命令的復制工作發(fā)生在返回命令回復之后讽膏, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那么主節(jié)點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡拄丰。 注意:Redis 集群可能會在將來提供同步寫的方法府树。 Redis 集群另外一種可能會丟失命令的情況是集群出現了網絡分區(qū), 并且一個客戶端與至少包括一個主節(jié)點在內的少數實例被孤立愈案。

舉個例子 假設集群包含 A 挺尾、 B 、 C 站绪、 A1 遭铺、 B1 、 C1 六個節(jié)點, 其中 A 魂挂、B 甫题、C 為主節(jié)點, A1 涂召、B1 坠非、C1 為A,B果正,C的從節(jié)點炎码, 還有一個客戶端 Z1 假設集群中發(fā)生網絡分區(qū),那么集群可能會分為兩方秋泳,大部分的一方包含節(jié)點 A 潦闲、C 、A1 迫皱、B1 和 C1 歉闰,小部分的一方則包含節(jié)點 B 和客戶端 Z1 .

Z1仍然能夠向主節(jié)點B中寫入, 如果網絡分區(qū)發(fā)生時間較短,那么集群將會繼續(xù)正常運作,如果分區(qū)的時間足夠讓大部分的一方將B1選舉為新的master,那么Z1寫入B中得數據便丟失了.

注意卓起, 在網絡分裂出現期間和敬, 客戶端 Z1 可以向主節(jié)點 B 發(fā)送寫命令的最大時間是有限制的, 這一時間限制稱為節(jié)點超時時間(node timeout)戏阅, 是 Redis 集群的一個重要的配置選項:

搭建并使用Redis集群

搭建集群的第一件事情我們需要一些運行在 集群模式的Redis實例. 這意味這集群并不是由一些普通的Redis實例組成的昼弟,集群模式需要通過配置啟用,開啟集群模式后的Redis實例便可以使用集群特有的命令和特性了.

下面是一個最少選項的集群的配置文件:

port 7000

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

文件中的 cluster-enabled 選項用于開實例的集群模式饲握, 而 cluster-conf-file 選項則設定了保存節(jié)點配置文件的路徑私杜, 默認值為 nodes.conf.節(jié)點配置文件無須人為修改, 它由 Redis 集群在啟動時創(chuàng)建救欧, 并在有需要時自動進行更新衰粹。

要讓集群正常運作至少需要三個主節(jié)點,不過在剛開始試用集群功能時笆怠, 強烈建議使用六個節(jié)點: 其中三個為主節(jié)點铝耻, 而其余三個則是各個主節(jié)點的從節(jié)點。

首先蹬刷, 讓我們進入一個新目錄瓢捉, 并創(chuàng)建六個以端口號為名字的子目錄, 稍后我們在將每個目錄中運行一個 Redis 實例: 命令如下:

mkdir cluster-test

cd cluster-test

mkdir 7000 7001 7002 7003 7004 7005

在文件夾 7000 至 7005 中办成, 各創(chuàng)建一個 redis.conf 文件泡态, 文件的內容可以使用上面的示例配置文件, 但記得將配置中的端口號從 7000 改為與文件夾名字相同的號碼迂卢。

從 Redis Github 頁面 的 unstable 分支中取出最新的 Redis 源碼某弦, 編譯出可執(zhí)行文件 redis-server 桐汤, 并將文件復制到 cluster-test 文件夾, 然后使用類似以下命令靶壮, 在每個標簽頁中打開一個實例:

cd 7000

../redis-server ./redis.conf

實例打印的日志顯示怔毛, 因為 nodes.conf 文件不存在, 所以每個節(jié)點都為它自身指定了一個新的 ID :

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

實例會一直使用同一個 ID 腾降, 從而在集群中保持一個獨一無二(unique)的名字拣度。

搭建集群

現在我們已經有了六個正在運行中的 Redis 實例, 接下來我們需要使用這些實例來創(chuàng)建集群螃壤, 并為每個節(jié)點編寫配置文件抗果。

通過使用 Redis 集群命令行工具 redis-trib , 編寫節(jié)點配置文件的工作可以非常容易地完成: redis-trib 位于 Redis 源碼的 src 文件夾中映穗, 它是一個 Ruby 程序窖张, 這個程序通過向實例發(fā)送特殊命令來完成創(chuàng)建新集群, 檢查集群蚁滋, 或者對集群進行重新分片(reshared)等工作。

./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

這個命令在這里用于創(chuàng)建一個新的集群, 選項–replicas 1 表示我們希望為集群中的每個主節(jié)點創(chuàng)建一個從節(jié)點赘淮。

之后跟著的其他參數則是這個集群實例的地址列表,3個master3個slave redis-trib 會打印出一份預想中的配置給你看辕录, 如果你覺得沒問題的話, 就可以輸入 yes 梢卸, redis-trib 就會將這份配置應用到集群當中,讓各個節(jié)點開始互相通訊,最后可以得到如下信息:

[OK] All 16384 slots covered

這表示集群中的 16384 個槽都有至少一個主節(jié)點在處理走诞, 集群運作正常。

Creating a Redis Cluster using the create-cluster script

If you don’t want to create a Redis Cluster by configuring and executing individual instances manually as explained above, there is a much simpler system (but you’ll not learn the same amount of operational details).

Just check?utils/create-cluster?directory in the Redis distribution. There is a script called?create-cluster?inside (same name as the directory it is contained into), it’s a simple bash script. In order to start a 6 nodes cluster with 3 masters and 3 slaves just type the following commands:

create-cluster start

create-cluster create

Reply to?yes?in step 2 when the?redis-trib?utility wants you to accept the cluster layout.

You can now interact with the cluster, the first node will start at port 30001 by default. When you are done, stop the cluster with:

create-cluster stop.

Please read the?README?inside this directory for more information on how to run the script.

使用集群

Redis 集群現階段的一個問題是客戶端實現很少蛤高。

以下是一些我知道的實現:

redis-rb-cluster?是我(@antirez)編寫的 Ruby 實現蚣旱, 用于作為其他實現的參考。 該實現是對 redis-rb 的一個簡單包裝戴陡, 高效地實現了與集群進行通訊所需的最少語義(semantic).

redis-py-cluster?看上去是 redis-rb-cluster 的一個 Python 版本塞绿, 這個項目有一段時間沒有更新了(最后一次提交是在六個月之前), 不過可以將這個項目用作學習集群的起點恤批。

流行的?Predis?曾經對早期的 Redis 集群有過一定的支持异吻, 但我不確定它對集群的支持是否完整, 也不清楚它是否和最新版本的 Redis 集群兼容 (因為新版的 Redis 集群將槽的數量從 4k 改為 16k 了).

使用最多的時java客戶端,?Jedis?最近添加了對集群的支持, 詳細請查看項目README中Jedis Cluster部分.

StackExchange.Redis?提供對 C# 的支持(并且包括大部分 .NET 下面的語言喜庞,比如: VB, F#等等)

thunk-redis?提供對 Node.js 和 io.js的支持诀浪。

Redis unstable 分支中的?redis-cli?程序實現了非常基本的集群支持延都, 可以使用命令 redis-cli -c 來啟動雷猪。

測試 Redis 集群比較簡單的辦法就是使用 redis-rb-cluster 或者 redis-cli , 接下來我們將使用 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"

注意:?如果你是使用腳本創(chuàng)建的集群節(jié)點晰房,那么默認端口可能是從30001開始求摇。

redis-cli 對集群的支持是非辰桶洌基本的, 所以它總是依靠 Redis 集群節(jié)點來將它轉向(redirect)至正確的節(jié)點月帝。一個真正的(serious)集群客戶端應該做得比這更好: 它應該用緩存記錄起哈希槽與節(jié)點地址之間的映射(map)躏惋, 從而直接將命令發(fā)送到正確的節(jié)點上面。這種映射只會在集群的配置出現某些修改時變化嚷辅, 比如說簿姨, 在一次故障轉移(failover)之后, 或者系統管理員通過添加節(jié)點或移除節(jié)點來修改了集群的布局(layout)之后簸搞, 諸如此類扁位。

使用redis-rb-cluster寫一個例子

在展示如何使用集群進行故障轉移、重新分片等操作之前趁俊, 我們需要創(chuàng)建一個示例應用域仇, 了解一些與 Redis 集群客戶端進行交互的基本方法。

在運行示例應用的過程中寺擂, 我們會嘗試讓節(jié)點進入失效狀態(tài)暇务, 又或者開始一次重新分片, 以此來觀察 Redis 集群在真實世界運行時的表現怔软, 并且為了讓這個示例盡可能地有用垦细, 我們會讓這個應用向集群進行寫操作。

本節(jié)將通過兩個示例應用來展示 redis-rb-cluster 的基本用法挡逼, 以下是本節(jié)的第一個示例應用括改, 它是一個名為 example.rb 的文件, 包含在redis-rb-cluster 項目里面

1? require './cluster'

2

3? startup_nodes = [

4? ? ? {:host => "127.0.0.1", :port => 7000},

5? ? ? {:host => "127.0.0.1", :port => 7001}

6? ]

7? rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)

8

9? last = false

10

11? while not last

12? ? ? begin

13? ? ? ? ? last = rc.get("__last__")

14? ? ? ? ? last = 0 if !last

15? ? ? rescue => e

16? ? ? ? ? puts "error #{e.to_s}"

17? ? ? ? ? sleep 1

18? ? ? end

19? end

20

21? ((last.to_i+1)..1000000000).each{|x|

22? ? ? begin

23? ? ? ? ? rc.set("foo#{x}",x)

24? ? ? ? ? puts rc.get("foo#{x}")

25? ? ? ? ? rc.set("__last__",x)

26? ? ? rescue => e

27? ? ? ? ? puts "error #{e.to_s}"

28? ? ? end

29? ? ? sleep 0.1

30? }

這個應用所做的工作非常簡單: 它不斷地以?foo<number>?為鍵家坎,?number?為值嘱能, 使用 SET 命令向數據庫設置鍵值對:

SET foo0 0

SET foo1 1

SET foo2 2

And so forth…

代碼中的每個集群操作都使用一個 begin 和 rescue 代碼塊(block)包裹著, 因為我們希望在代碼出錯時虱疏, 將錯誤打印到終端上面惹骂, 而不希望應用因為異常(exception)而退出。

代碼的第七行是代碼中第一個有趣的地方订框, 它創(chuàng)建了一個 Redis 集群對象析苫, 其中創(chuàng)建對象所使用的參數及其意義如下:第一個參數是記錄了啟動節(jié)點的 startup_nodes 列表, 列表中包含了兩個集群節(jié)點的地址穿扳。第二個參數指定了對于集群中的各個不同的節(jié)點衩侥, Redis 集群對象可以獲得的最大連接數 ,第三個參數 timeout 指定了一個命令在執(zhí)行多久之后矛物, 才會被看作是執(zhí)行失敗茫死。

啟動列表中并不需要包含所有集群節(jié)點的地址, 但這些地址中至少要有一個是有效的: 一旦 redis-rb-cluster 成功連接上集群中的某個節(jié)點時履羞, 集群節(jié)點列表就會被自動更新峦萎, 任何真正的的集群客戶端都應該這樣做屡久。

現在, 程序創(chuàng)建的 Redis 集群對象實例被保存到 rc 變量里面爱榔, 我們可以將這個對象當作普通 Redis 對象實例來使用被环。

在十一至十九行, 我們先嘗試閱讀計數器中的值详幽, 如果計數器不存在的話筛欢, 我們才將計數器初始化為 0 : 通過將計數值保存到 Redis 的計數器里面, 我們可以在示例重啟之后唇聘, 仍然繼續(xù)之前的執(zhí)行過程版姑, 而不必每次重啟之后都從 foo0 開始重新設置鍵值對。為了讓程序在集群下線的情況下迟郎, 仍然不斷地嘗試讀取計數器的值剥险, 我們將讀取操作包含在了一個 while 循環(huán)里面, 一般的應用程序并不需要如此小心宪肖。

二十一至三十行是程序的主循環(huán)表制, 這個循環(huán)負責設置鍵值對, 并在設置出錯時打印錯誤信息匈庭。程序在主循環(huán)的末尾添加了一個 sleep 調用夫凸, 讓寫操作的執(zhí)行速度變慢, 幫助執(zhí)行示例的人更容易看清程序的輸出阱持。執(zhí)行 example.rb 程序將產生以下輸出:

ruby ./example.rb

1

2

3

4

5

6

7

8

9

^C (I stopped the program here)

這個程序并不是十分有趣, 稍后我們就會看到一個更有趣的集群應用示例魔熏, 不過在此之前衷咽, 讓我們先使用這個示例來演示集群的重新分片操作。

集群重新分片

現在蒜绽, 讓我們來試試對集群進行重新分片操作镶骗。在執(zhí)行重新分片的過程中, 請讓你的 example.rb 程序處于運行狀態(tài)躲雅, 這樣你就會看到鼎姊, 重新分片并不會對正在運行的集群程序產生任何影響, 你也可以考慮將 example.rb 中的 sleep 調用刪掉相赁, 從而讓重新分片操作在近乎真實的寫負載下執(zhí)行 重新分片操作基本上就是將某些節(jié)點上的哈希槽移動到另外一些節(jié)點上面相寇, 和創(chuàng)建集群一樣, 重新分片也可以使用 redis-trib 程序來執(zhí)行 執(zhí)行以下命令可以開始一次重新分片操作:

./redis-trib.rb reshard 127.0.0.1:7000

你只需要指定集群中其中一個節(jié)點的地址钮科, redis-trib 就會自動找到集群中的其他節(jié)點唤衫。

目前 redis-trib 只能在管理員的協助下完成重新分片的工作, 要讓 redis-trib 自動將哈希槽從一個節(jié)點移動到另一個節(jié)點绵脯, 目前來說還做不到

你想移動多少個槽( 從1 到 16384)?

我們嘗試從將100個槽重新分片佳励, 如果 example.rb 程序一直運行著的話休里, 現在 1000 個槽里面應該有不少鍵了。

除了移動的哈希槽數量之外赃承, redis-trib 還需要知道重新分片的目標妙黍, 也即是, 負責接收這 1000 個哈希槽的節(jié)點瞧剖。

$ redis-cli -p 7000 cluster nodes | grep myself

97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5460

我的目標節(jié)點是 97a3a64667477371c4479320d683e4c8db5858b1.

現在需要指定從哪些節(jié)點來移動keys到目標節(jié)點 我輸入的是all 拭嫁,這樣就會從其他每個master上取一些哈希槽。

最后確認后你將會看到每個redis-trib移動的槽的信息筒繁,每個key的移動的信息也會打印出來 在重新分片的過程中噩凹,你的例子程序是不會受到影響的,你可以停止或者重新啟動多次。

在重新分片結束后你可以通過如下命令檢查集群狀態(tài):

./redis-trib.rb check 127.0.0.1:7000

一個更有趣的程序

我們在前面使用的示例程序 example.rb 并不是十分有趣毡咏, 因為它只是不斷地對集群進行寫入驮宴, 但并不檢查寫入結果是否正確。 比如說呕缭, 集群可能會錯誤地將 example.rb 發(fā)送的所有 SET 命令都改成了 SET foo 42 堵泽, 但因為 example.rb 并不檢查寫入后的值, 所以它不會意識到集群實際上寫入的值是錯誤的 因為這個原因恢总, redis-rb-cluster 項目包含了一個名為 consistency-test.rb 的示例應用迎罗, 這個應用比起 example.rb 有趣得多: 它創(chuàng)建了多個計數器(默認為 1000 個), 并通過發(fā)送 INCR 命令來增加這些計數器的值片仿。

在增加計數器值的同時纹安, consistency-test.rb 還執(zhí)行以下操作: 每次使用 INCR 命令更新一個計數器時, 應用會記錄下計數器執(zhí)行 INCR 命令之后應該有的值砂豌。 舉個例子厢岂, 如果計數器的起始值為 0 , 而這次是程序第 50 次向它發(fā)送 INCR 命令阳距, 那么計數器的值應該是 50 塔粒。

在每次發(fā)送 INCR 命令之前, 程序會隨機從集群中讀取一個計數器的值筐摘, 并將它與自己記錄的值進行對比卒茬, 看兩個值是否相同。

換句話說咖熟, 這個程序是一個一致性檢查器(consistency checker): 如果集群在執(zhí)行 INCR 命令的過程中圃酵, 丟失了某條 INCR 命令, 又或者多執(zhí)行了某條客戶端沒有確認到的 INCR 命令球恤, 那么檢查器將察覺到這一點 —— 在前一種情況中辜昵, consistency-test.rb 記錄的計數器值將比集群記錄的計數器值要大; 而在后一種情況中咽斧, consistency-test.rb 記錄的計數器值將比集群記錄的計數器值要小堪置。

運行 consistency-test 程序將產生類似以下的輸出:

$ 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í)行的讀和 寫,和錯誤(由于系統不可用而沒有接受的查詢發(fā)生的錯誤)的數量.

如果程序察覺了不一致的情況出現躬存, 它將在輸出行的末尾顯式不一致的詳細情況。比如說舀锨, 如果我們在 consistency-test.rb 運行的過程中岭洲, 手動修改某個計數器的值:

$ redis 127.0.0.1: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 |

在我們修改計數器值的時候, 計數器的正確值是 114 (執(zhí)行了 114 次 INCR 命令)坎匿, 因為我們將計數器的值設成了 0 盾剩, 所以 consistency-test.rb 會向我們報告說丟失了 114 個 INCR 命令。

這個程序作為測試程序很有意思替蔬,所以我們用這個程序來測試故障恢復.

測試故障轉移

在執(zhí)行本節(jié)操作的過程中告私, 請一直運行 consistency-test 程序。 要觸發(fā)一次故障轉移承桥, 最簡單的辦法就是令集群中的某個主節(jié)點進入下線狀態(tài)驻粟。首先用以下命令列出集群中的所有主節(jié)點:

$ 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

通過命令輸出得知端口號為 7000 、 7001 和 7002 的節(jié)點都是主節(jié)點凶异, 然后我們可以通過向端口號為7002 的主節(jié)點發(fā)送?DEBUG SEGFAULT?命令蜀撑, 讓這個主節(jié)點崩潰:

$ redis-cli -p 7002 debug segfault

Error: Server closed the connection

現在,切換到運行著 consistency-test 的標簽頁剩彬, 可以看到酷麦, consistency-test 在 7002 下線之后的一段時間里將產生大量的錯誤警告信息:

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) |

從 consistency-test 的這段輸出可以看到, 集群在執(zhí)行故障轉移期間喉恋, 總共丟失了 578 個讀命令和 577 個寫命令沃饶, 但是并沒有產生任何數據不一致。這聽上去可能有點奇怪轻黑, 因為在教程的開頭我們提到過绍坝, Redis 使用的是異步復制, 在執(zhí)行故障轉移期間苔悦, 集群可能會丟失寫命令。但是在實際上椎咧, 丟失命令的情況并不常見玖详, 因為 Redis 幾乎是同時執(zhí)行將命令回復發(fā)送給客戶端, 以及將命令復制給從節(jié)點這兩個操作勤讽, 所以實際上造成命令丟失的時間窗口是非常小的蟋座。不過, 盡管出現的幾率不高脚牍, 但丟失命令的情況還是有可能會出現的向臀, 所以我們對 Redis 集群不能提供強一致性的這一描述仍然是正確的。現在诸狭, 讓我們使用 cluster nodes 命令,查看集群在執(zhí)行故障轉移操作之后券膀, 主從節(jié)點的布局情況:

$ 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

現在masters運行在 7000, 7001 和 7005端口上. 原來的master 7002現在變成了一個7005的一個從節(jié)點.

CLUSTER NODES?命令的輸出看起來有點復雜,其實他非常的簡單君纫,含義如下:

節(jié)點ID

IP:端口

標志: master, slave, myself, fail, …

如果是個從節(jié)點, 這里是它的主節(jié)點的NODE ID

集群最近一次向節(jié)點發(fā)送 PING 命令之后, 過去了多長時間還沒接到回復芹彬。.

節(jié)點最近一次返回 PONG 回復的時間蓄髓。

節(jié)點的配置紀元(configuration epoch):詳細信息請參考 Redis 集群規(guī)范 。

本節(jié)點的網絡連接情況:例如 connected 舒帮。

節(jié)點目前包含的槽:例如 127.0.0.1:7001 目前包含號碼為 5960 至 10921 的哈希槽会喝。

手動故障轉移

有的時候在主節(jié)點沒有任何問題的情況下強制手動故障轉移也是很有必要的,比如想要升級主節(jié)點的Redis進程玩郊,我們可以通過故障轉移將其轉為slave再進行升級操作來避免對集群的可用性造成很大的影響肢执。

Redis集群使用 CLUSTER FAILOVER命令來進行故障轉移,不過要被轉移的主節(jié)點的從節(jié)點上執(zhí)行該命令 手動故障轉移比主節(jié)點失敗自動故障轉移更加安全译红,因為手動故障轉移時客戶端的切換是在確保新的主節(jié)點完全復制了失敗的舊的主節(jié)點數據的前提下下發(fā)生的预茄,所以避免了數據的丟失。

執(zhí)行手動故障轉移時從節(jié)點日志如下:

# 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.

其基本過程如下:客戶端不再鏈接我們淘汰的主節(jié)點临庇,同時主節(jié)點向從節(jié)點發(fā)送復制偏移量,從節(jié)點得到復制偏移量后故障轉移開始,接著通知主節(jié)點進行配置切換,當客戶端在舊的master上解鎖后重新連接到新的主節(jié)點上反璃。

添加一個新節(jié)點

添加新的節(jié)點的基本過程就是添加一個空的節(jié)點然后移動一些數據給它,有兩種情況假夺,添加一個主節(jié)點和添加一個從節(jié)點(添加從節(jié)點時需要將這個新的節(jié)點設置為集群中某個節(jié)點的復制)

針對這兩種情況淮蜈,本節(jié)都會介紹,先從添加主節(jié)點開始.

兩種情況第一步都是要添加 一個空的節(jié)點.

啟動新的7006節(jié)點,使用的配置文件和以前的一樣,只要把端口號改一下即可已卷,過程如下:

在終端打開一個新的標簽頁.

進入cluster-test 目錄.

創(chuàng)建并進入 7006文件夾.

和其他節(jié)點一樣梧田,創(chuàng)建redis.conf文件,需要將端口號改成7006.

最后啟動節(jié)點 ../redis-server ./redis.conf

如果正常的話,節(jié)點會正確的啟動.

接下來使用redis-trib 來添加這個節(jié)點到現有的集群中去.

./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

可以看到.使用addnode命令來添加節(jié)點侧蘸,第一個參數是新節(jié)點的地址裁眯,第二個參數是任意一個已經存在的節(jié)點的IP和端口. 我們可以看到新的節(jié)點已經添加到集群中:

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

新節(jié)點現在已經連接上了集群, 成為集群的一份子讳癌, 并且可以對客戶端的命令請求進行轉向了穿稳, 但是和其他主節(jié)點相比, 新節(jié)點還有兩點區(qū)別:

新節(jié)點沒有包含任何數據晌坤, 因為它沒有包含任何哈希槽.

盡管新節(jié)點沒有包含任何哈希槽逢艘, 但它仍然是一個主節(jié)點, 所以在集群需要將某個從節(jié)點升級為新的主節(jié)點時骤菠, 這個新節(jié)點不會被選中它改。

接下來, 只要使用 redis-trib 程序商乎, 將集群中的某些哈希桶移動到新節(jié)點里面央拖, 新節(jié)點就會成為真正的主節(jié)點了。

添加一個從節(jié)點

有兩種方法添加從節(jié)點,可以像添加主節(jié)點一樣使用redis-trib 命令鲜戒,也可以像下面的例子一樣使用 –slave選項:

./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:7000

此處的命令和添加一個主節(jié)點命令類似专控,此處并沒有指定添加的這個從節(jié)點的主節(jié)點,這種情況下系統會在其他的復制集中的主節(jié)點中隨機選取一個作為這個從節(jié)點的主節(jié)點袍啡。

你可以通過下面的命令指定主節(jié)點:

./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000

也可以使用CLUSTER REPLICATE 命令添加.這個命令也可以改變一個從節(jié)點的主節(jié)點踩官。

例如,要給主節(jié)點 127.0.0.1:7005添加一個從節(jié)點境输,該節(jié)點哈希槽的范圍1423-16383, 節(jié)點 ID 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,我們需要鏈接新的節(jié)點(已經是空的主節(jié)點)并執(zhí)行命令:

redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

我們新的從節(jié)點有了一些哈希槽蔗牡,其他的節(jié)點也知道(過幾秒后會更新他們自己的配置),可以使用如下命令確認:

$ 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é)點 3c3a0c… 有兩個從節(jié)點嗅剖, 7002 (已經存在的) 和 7006 (新添加的).

移除一個節(jié)點

只要使用?del-node?命令即可:

./redis-trib del-node 127.0.0.1:7000 `<node-id>`

第一個參數是任意一個節(jié)點的地址,第二個節(jié)點是你想要移除的節(jié)點地址辩越。

使用同樣的方法移除主節(jié)點,不過在移除主節(jié)點前,需要確保這個主節(jié)點是空的. 如果不是空的,需要將這個節(jié)點的數據重新分片到其他主節(jié)點上.

替代移除主節(jié)點的方法是手動執(zhí)行故障恢復信粮,被移除的主節(jié)點會作為一個從節(jié)點存在黔攒,不過這種情況下不會減少集群節(jié)點的數量,也需要重新分片數據.

從節(jié)點的遷移

在Redis集群中會存在改變一個從節(jié)點的主節(jié)點的情況强缘,需要執(zhí)行如下命令 :

CLUSTER REPLICATE <master-node-id>

在特定的場景下督惰,不需要系統管理員的協助下,自動將一個從節(jié)點從當前的主節(jié)點切換到另一個主節(jié) 的自動重新配置的過程叫做復制遷移(從節(jié)點遷移)旅掂,從節(jié)點的遷移能夠提高整個Redis集群的可用性.

你可以閱讀(Redis集群規(guī)范)/topics/cluster-spec了解細節(jié).

簡短的概況一下從節(jié)點遷移

集群會在有從節(jié)點數量最多的主節(jié)點上進行從節(jié)點的遷移.

要在一個主節(jié)點上添加多個從節(jié)點.

參數來控制從節(jié)點遷移 replica-migration-barrier:你可以仔細閱讀redis.conf 赏胚。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市商虐,隨后出現的幾起案子觉阅,更是在濱河造成了極大的恐慌,老刑警劉巖秘车,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典勇,死亡現場離奇詭異,居然都是意外死亡叮趴,警方通過查閱死者的電腦和手機割笙,發(fā)現死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眯亦,“玉大人咳蔚,你說我怎么就攤上這事∩ν眨” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵侈询,是天一觀的道長舌涨。 經常有香客問我,道長,這世上最難降的妖魔是什么囊嘉? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任温技,我火速辦了婚禮,結果婚禮上扭粱,老公的妹妹穿的比我還像新娘舵鳞。我一直安慰自己,他們只是感情好琢蛤,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布蜓堕。 她就那樣靜靜地躺著,像睡著了一般博其。 火紅的嫁衣襯著肌膚如雪套才。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天慕淡,我揣著相機與錄音背伴,去河邊找鬼。 笑死峰髓,一個胖子當著我的面吹牛傻寂,可吹牛的內容都是我干的。 我是一名探鬼主播携兵,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼疾掰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起苹熏,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤骄呼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后巴柿,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡死遭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年广恢,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呀潭。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡钉迷,死狀恐怖,靈堂內的尸體忽然破棺而出钠署,到底是詐尸還是另有隱情糠聪,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布谐鼎,位于F島的核電站舰蟆,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜身害,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一味悄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塌鸯,春花似錦侍瑟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至淮悼,卻和暖如春咐低,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袜腥。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工见擦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羹令。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓鲤屡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親福侈。 傳聞我的和親對象是個殘疾皇子酒来,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345