redis分片機制

  所謂的分片其實就是大的數據分成幾個小的部分,分別放置存儲,對於數據而言無外乎就是讀寫,讀寫的基礎就是數據的定位,redis利用集羣的方式+槽位完成,分片的數據的定位和管理維護。

   Redis 集羣是一個可以在多個 Redis 節點之間進行數據共享的設施(installation)。

Redis 集羣使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集羣包含 16384 個哈希槽(hash slot), 數據庫中的每個鍵都屬於這 16384 個哈希槽的其中一個, 集羣使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽, 其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。

1. 槽位分配

集羣中的每個節點負責處理一部分哈希槽。 舉個例子, 一個集羣可以有三個哈希槽, 其中:

  • 節點 A 負責處理 0 號至 5500 號哈希槽。
  • 節點 B 負責處理 5501 號至 11000 號哈希槽。
  • 節點 C 負責處理 11001 號至 16384 號哈希槽。

這種將哈希槽分佈到不同節點的做法使得用戶可以很容易地向集羣中添加或者刪除節點。 比如說:

  • 如果用戶將新節點 D 添加到集羣中, 那麼集羣只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
  • 與此類似, 如果用戶要從集羣中移除節點 A , 那麼集羣只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然後再移除空白(不包含任何哈希槽)的節點 A 就可以了。

因爲將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集羣下線。

  2.高可用性

爲了使得集羣在一部分節點下線或者無法與集羣的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作, Redis 集羣對節點使用了主從複製功能: 集羣中的每個節點都有 1 個至 N 個複製品(replica), 其中一個複製品爲主節點(master), 而其餘的 N-1 個複製品爲從節點(slave)。

在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那麼集羣將無法正常運行, 因爲集羣找不到節點來處理 5501 號至 11000號的哈希槽。

另一方面, 假如在創建集羣的時候(或者至少在節點 B 下線之前), 我們爲主節點 B 添加了從節點 B1 , 那麼當主節點 B 下線的時候, 集羣就會將 B1 設置爲新的主節點, 並讓它代替下線的主節點 B , 繼續處理 5501 號至 11000 號的哈希槽, 這樣集羣就不會因爲主節點 B 的下線而無法正常運作了。

不過如果節點 B 和 B1 都下線的話, Redis 集羣還是會停止運作

3.一致性保證(非強一致性)

Redis 集羣不保證數據的強一致性(strong consistency): 在特定條件下, Redis 集羣可能會丟失已經被執行過的寫命令。

使用異步複製(asynchronous replication)是 Redis 集羣可能會丟失寫命令的其中一個原因。 考慮以下這個寫命令的例子:

  • 客戶端向主節點 B 發送一條寫命令。
  • 主節點 B 執行寫命令,並向客戶端返回命令回覆。
  • 主節點 B 將剛剛執行的寫命令複製給它的從節點 B1 、 B2 和 B3 。

如你所見, 主節點對命令的複製工作發生在返回命令回覆之後, 因爲如果每次處理命令請求都需要等待複製操作完成的話, 那麼主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。

4.創建集羣(不詳說啦,參照我的另一篇博客)

現在我們已經有了六個正在運行中的 Redis 實例, 接下來我們需要使用這些實例來創建集羣, 併爲每個節點編寫配置文件。

通過使用 Redis 集羣命令行工具 redis-trib , 編寫節點配置文件的工作可以非常容易地完成: redis-trib 位於 Redis 源碼的 src 文件夾中, 它是一個 Ruby 程序, 這個程序通過向實例發送特殊命令來完成創建新集羣, 檢查集羣, 或者對集羣進行重新分片(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

命令的意義如下:

  • 給定 redis-trib.rb 程序的命令是 create , 這表示我們希望創建一個新的集羣。
  • 選項 --replicas 1 表示我們希望爲集羣中的每個主節點創建一個從節點。
  • 之後跟着的其他參數則是實例的地址列表, 我們希望程序使用這些地址所指示的實例來創建新集羣。

簡單來說, 以上命令的意思就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集羣。

接着, redis-trib 會打印出一份預想中的配置給你看, 如果你覺得沒問題的話, 就可以輸入 yes , redis-trib 就會將這份配置應用到集羣當中:

>>> Creating cluster
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7000 replica #1 is 127.0.0.1:7003
127.0.0.1:7001 replica #1 is 127.0.0.1:7004
127.0.0.1:7002 replica #1 is 127.0.0.1:7005
M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001
slots:5461-10921 (5461 slots) master
M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002
slots:10922-16383 (5462 slots) master
S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003
S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004
S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005
Can I set the above configuration? (type 'yes' to accept): yes

輸入 yes 並按下回車確認之後, 集羣就會將配置應用到各個節點, 並連接起(join)各個節點 —— 也即是, 讓各個節點開始互相通訊:

>>> Nodes configuration updated
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001
slots:5461-10921 (5461 slots) master
M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002
slots:10922-16383 (5462 slots) master
M: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003
slots: (0 slots) master
M: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004
slots: (0 slots) master
M: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005
slots: (0 slots) master
[OK] All nodes agree about slots configuration.

如果一切正常的話, redis-trib 將輸出以下信息:

>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

這表示集羣中的 16384 個槽都有至少一個主節點在處理, 集羣運作正常。

5.重新分區

現在, 讓我們來試試對集羣進行重新分片操作。

在執行重新分片的過程中, 請讓你的 example.rb 程序處於運行狀態, 這樣你就會看到, 重新分片並不會對正在運行的集羣程序產生任何影響, 你也可以考慮將 example.rb 中的 sleep 調用刪掉, 從而讓重新分片操作在近乎真實的寫負載下執行。

重新分片操作基本上就是將某些節點上的哈希槽移動到另外一些節點上面, 和創建集羣一樣, 重新分片也可以使用 redis-trib 程序來執行。

執行以下命令可以開始一次重新分片操作:

$ ./redis-trib.rb reshard 127.0.0.1:7000

你只需要指定集羣中其中一個節點的地址, redis-trib 就會自動找到集羣中的其他節點。

目前 redis-trib 只能在管理員的協助下完成重新分片的工作, 要讓 redis-trib 自動將哈希槽從一個節點移動到另一個節點, 目前來說還做不到 (不過實現這個功能並不難)。

執行 redis-trib 的第一步就是設定你打算移動的哈希槽的數量:

$ ./redis-trib.rb reshard 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002
slots:10922-16383 (5462 slots) master
S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005
slots: (0 slots) slave
M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001
slots:5461-10921 (5461 slots) master
S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003
slots: (0 slots) slave
S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004
slots: (0 slots) slave
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 1000

我們將打算移動的槽數量設置爲 1000 個, 如果 example.rb 程序一直運行着的話, 現在 1000 個槽裏面應該有不少鍵了。

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

指定目標需要使用節點的 ID , 而不是 IP 地址和端口。 比如說, 我們打算使用集羣的第一個主節點來作爲目標, 它的 IP 地址和端口是 127.0.0.1:7000 , 而節點 ID 則是 9991306f0e50640a5684f1958fd754b38fa034c9 , 那麼我們應該向 redis-trib 提供節點的 ID :

$ ./redis-trib.rb reshard 127.0.0.1:7000
...
What is the receiving node ID? 9991306f0e50640a5684f1958fd754b38fa034c9

redis-trib 會打印出集羣中所有節點的 ID , 並且我們也可以通過執行以下命令來獲得節點的運行 ID :

$ ./redis-cli -p 7000 cluster nodes | grep myself
9991306f0e50640a5684f1958fd754b38fa034c9 :0 myself,master - 0 0 0 connected 0-5460

接着, redis-trib 會向你詢問重新分片的源節點(source node), 也即是, 要從哪個節點中取出 1000 個哈希槽, 並將這些槽移動到目標節點上面。

如果我們不打算從特定的節點上取出指定數量的哈希槽, 那麼可以向 redis-trib 輸入 all , 這樣的話, 集羣中的所有主節點都會成爲源節點, redis-trib 將從各個源節點中各取出一部分哈希槽, 湊夠 1000 個, 然後移動到目標節點上面:

$ ./redis-trib.rb reshard 127.0.0.1:7000
...
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:all

輸入 all 並按下回車之後, redis-trib 將打印出哈希槽的移動計劃, 如果你覺得沒問題的話, 就可以輸入 yes 並再次按下回車:

$ ./redis-trib.rb reshard 127.0.0.1:7000
...
Moving slot 11421 from 393c6df5eb4b4cec323f0e4ca961c8b256e3460a
Moving slot 11422 from 393c6df5eb4b4cec323f0e4ca961c8b256e3460a
Moving slot 5461 from e68e52cee0550f558b03b342f2f0354d2b8a083b
Moving slot 5469 from e68e52cee0550f558b03b342f2f0354d2b8a083b
...
Moving slot 5959 from e68e52cee0550f558b03b342f2f0354d2b8a083b
Do you want to proceed with the proposed reshard plan (yes/no)? yes

輸入 yes 並使用按下回車之後, redis-trib 就會正式開始執行重新分片操作, 將指定的哈希槽從源節點一個個地移動到目標節點上面:

$ ./redis-trib.rb reshard 127.0.0.1:7000
...
Moving slot 5934 from 127.0.0.1:7001 to 127.0.0.1:7000:
Moving slot 5935 from 127.0.0.1:7001 to 127.0.0.1:7000:
Moving slot 5936 from 127.0.0.1:7001 to 127.0.0.1:7000:
Moving slot 5937 from 127.0.0.1:7001 to 127.0.0.1:7000:
...
Moving slot 5959 from 127.0.0.1:7001 to 127.0.0.1:7000:

在重新分片的過程中, example.rb 應該可以繼續正常運行, 不會出現任何問題。

在重新分片操作執行完畢之後, 可以使用以下命令來檢查集羣是否正常:

$ ./redis-trib.rb check 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000
slots:0-5959,10922-11422 (6461 slots) master
M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002
slots:11423-16383 (4961 slots) master
S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005
slots: (0 slots) slave
M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001
slots:5960-10921 (4962 slots) master
S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003
slots: (0 slots) slave
S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004
slots: (0 slots) slave
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

根據檢查結果顯示, 集羣運作正常。

需要注意的就是, 在三個主節點中, 節點 127.0.0.1:7000 包含了 6461 個哈希槽, 而節點 127.0.0.1:7001 和節點 127.0.0.1:7002 都只包含了 4961 個哈希槽, 因爲後兩者都將自己的 500 個哈希槽移動到了節點 127.0.0.1:7000 。

6.添加新的節點(特地放在5之後)

根據新添加節點的種類, 我們需要用兩種方法來將新節點添加到集羣裏面:

  • 如果要添加的新節點是一個主節點, 那麼我們需要創建一個空節點(empty node), 然後將某些哈希桶移動到這個空節點裏面。
  • 另一方面, 如果要添加的新節點是一個從節點, 那麼我們需要將這個新節點設置爲集羣中某個節點的複製品(replica)。

本節將對以上兩種情況進行介紹, 首先介紹主節點的添加方法, 然後再介紹從節點的添加方法。

無論添加的是那種節點, 第一步要做的總是添加一個空節點。

我們可以繼續使用之前啓動 127.0.0.1:7000 、 127.0.0.1:7001 等節點的方法, 創建一個端口號爲 7006 的新節點, 使用的配置文件也和之前一樣, 只是記得要將配置中的端口號改爲 7000 。

以下是啓動端口號爲 7006 的新節點的詳細步驟:

  1. 在終端裏創建一個新的標籤頁。
  2. 進入 cluster-test 文件夾。
  3. 創建並進入 7006 文件夾。
  4. 將 redis.conf 文件複製到 7006 文件夾裏面,然後將配置中的端口號選項改爲 7006 。
  5. 使用命令 ../../redis-server redis.conf 啓動節點。

如果一切正常, 那麼節點應該會正確地啓動。

接下來, 執行以下命令, 將這個新節點添加到集羣裏面:

./redis-trib.rb addnode 127.0.0.1:7006 127.0.0.1:7000

命令中的 addnode 表示我們要讓 redis-trib 將一個節點添加到集羣裏面, addnode 之後跟着的是新節點的 IP 地址和端口號, 再之後跟着的是集羣中任意一個已存在節點的 IP 地址和端口號, 這裏我們使用的是 127.0.0.1:7000 。

通過 cluster nodes 命令, 我們可以確認新節點 127.0.0.1:7006 已經被添加到集羣裏面了:

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

新節點現在已經連接上了集羣, 成爲集羣的一份子, 並且可以對客戶端的命令請求進行轉向了, 但是和其他主節點相比, 新節點還有兩點區別:

  • 新節點沒有包含任何數據, 因爲它沒有包含任何哈希桶。
  • 儘管新節點沒有包含任何哈希桶, 但它仍然是一個主節點, 所以在集羣需要將某個從節點升級爲新的主節點時, 這個新節點不會被選中。

接下來, 只要使用 redis-trib 程序, 將集羣中的某些哈希桶移動到新節點裏面, 新節點就會成爲真正的主節點了。

因爲使用 redis-trib 移動哈希桶的方法在前面已經介紹過, 所以這裏就不再重複介紹了。

現在, 讓我們來看看, 將一個新節點轉變爲某個主節點的複製品(也即是從節點)的方法。

舉個例子, 如果我們打算讓新節點成爲 127.0.0.1:7005 的從節點, 那麼我們只要用客戶端連接上新節點, 然後執行以下命令就可以了:

redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

其中命令提供的 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 就是主節點 127.0.0.1:7005 的節點 ID 。

執行 cluster replicate 命令之後, 我們可以使用以下命令來確認 127.0.0.1:7006 已經成爲了 ID 爲 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 。

https://www.cnblogs.com/wxd0108/p/5729754.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章