歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Redis 集群教程

Redis 集群教程

日期:2017/2/27 15:57:29   编辑:Linux教程
本文檔是Redis集群的入門教程, 從用戶的角度介紹了設置、測試和操作集群的方法。

本教程不包含晦澀難懂的分布式概念, 也沒有像Redis 集群規范那樣包含Redis 集群的實現細節, 如果你打算深入地學習 Redis 集群的部署方法, 那麼推薦你在閱讀完這個教程之後, 再去看一看集群規范。

Redis 集群目前仍處於Alpha測試版本, 如果在使用過程中發現任何問題, 請到Redis 郵件列表 發貼, 或者到Redis的Github頁面報告錯誤。

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

Redis 集群不支持那些需要同時處理多個鍵的 Redis 命令, 因為執行這些命令需要在多個 Redis 節點之間移動數據, 並且在高負載的情況下, 這些命令將降低 Redis 集群的性能, 並導致不可預測的行為。

Redis 集群通過分區(partition)來提供一定程度的可用性(availability): 即使集群中有一部分節點失效或者無法進行通訊, 集群也可以繼續處理命令請求。

Redis 集群提供了以下兩個好處:
  • 將數據自動切分(split)到多個節點的能力。
  • 當集群中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力。

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

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

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

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

  • 如果用戶將新節點 D 添加到集群中, 那麼集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
  • 與此類似, 如果用戶要從集群中移除節點 A , 那麼集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然後再移除空白(不包含任何哈希槽)的節點 A 就可以了。
因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。

Redis 集群中的主從復制
為了使得集群在一部分節點下線或者無法與集群的大多數(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 集群還是會停止運作。

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

使用異步復制(asynchronous replication)是 Redis 集群可能會丟失寫命令的其中一個原因。 考慮以下這個寫命令的例子:
  • 客戶端向主節點 B 發送一條寫命令。
  • 主節點 B 執行寫命令,並向客戶端返回命令回復。
  • 主節點 B 將剛剛執行的寫命令復制給它的從節點 B1 、 B2 和 B3 。
如你所見, 主節點對命令的復制工作發生在返回命令回復之後, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那麼主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。

如果真的有必要的話, Redis 集群可能會在將來提供同步地(synchronou)執行寫命令的方法。

Redis 集群另外一種可能會丟失命令的情況是, 集群出現網絡分裂(network partition), 並且一個客戶端與至少包括一個主節點在內的少數(minority)實例被孤立。

舉個例子, 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, 而 A1 、B1 、C1 分別為三個主節點的從節點, 另外還有一個客戶端 Z1 。

假設集群中發生網絡分裂, 那麼集群可能會分裂為兩方, 大多數(majority)的一方包含節點 A 、C 、A1 、B1 和 C1 , 而少數(minority)的一方則包含節點 B 和客戶端 Z1 。

在網絡分裂期間, 主節點 B 仍然會接受 Z1 發送的寫命令:

  • 如果網絡分裂出現的時間很短, 那麼集群會繼續正常運行;
  • 但是, 如果網絡分裂出現的時間足夠長, 使得大多數一方將從節點 B1 設置為新的主節點, 並使用 B1 來代替原來的主節點 B , 那麼 Z1 發送給主節點 B 的寫命令將丟失。

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

  • 對於大多數一方來說, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那麼集群會將這個主節點視為下線, 並使用從節點來代替這個主節點繼續工作。
  • 對於少數一方, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那麼它將停止處理寫命令, 並向客戶端報告錯誤。

創建並使用 Redis 集群
Redis 集群由多個運行在集群模式(cluster mode)下的 Redis 實例組成, 實例的集群模式需要通過配置來開啟, 開啟集群模式的實例將可以使用集群特有的功能和命令。

以下是一個包含了最少選項的集群配置文件示例:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
文件中的 cluster-enabled 選項用於開實例的集群模式, 而 cluster-conf-file 選項則設定了保存節點配置文件的路徑, 默認值為 nodes.conf 。

節點配置文件無須人為修改, 它由 Redis 集群在啟動時創建, 並在有需要時自動進行更新。

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

首先, 讓我們進入一個新目錄, 並創建六個以端口號為名字的子目錄, 稍後我們在將每個目錄中運行一個 Redis 實例:
mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005

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

現在, 從 Redis Github 頁面 的 unstable 分支中取出最新的 Redis 源碼, 編譯出可執行文件 redis-server , 並將文件復制到 cluster-test 文件夾, 然後使用類似以下命令, 在每個標簽頁中打開一個實例:
cd 7000
../redis-server ./redis.conf

實例打印的日志顯示, 因為 nodes.conf 文件不存在, 所以每個節點都為它自身指定了一個新的 ID :
[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1

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

每個節點都使用 ID 而不是 IP 或者端口號來記錄其他節點, 因為 IP 地址和端口號都可能會改變, 而這個獨一無二的標識符(identifier)則會在節點的整個生命周期中一直保持不變。

我們將這個標識符稱為節點 ID

創建集群
現在我們已經有了六個正在運行中的 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 會打印出一份預想中的配置給你看, 如果你覺得沒問題的話, 就可以輸入 yesredis-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 個槽都有至少一個主節點在處理, 集群運作正常。

集群的客戶端
Redis 集群現階段的一個問題是客戶端實現很少。 以下是一些我知道的實現:
  • redis-rb-cluster 是我(@antirez)編寫的 Ruby 實現, 用於作為其他實現的參考。 該實現是對 redis-rb 的一個簡單包裝, 高效地實現了與集群進行通訊所需的最少語義(semantic)。
  • redis-py-cluster 看上去是 redis-rb-cluster 的一個 Python 版本, 這個項目有一段時間沒有更新了(最後一次提交是在六個月之前), 不過可以將這個項目用作學習集群的起點。
  • 流行的 Predis 曾經對早期的 Redis 集群有過一定的支持, 但我不確定它對集群的支持是否完整, 也不清楚它是否和最新版本的 Redis 集群兼容 (因為新版的 Redis 集群將槽的數量從 4k 改為 16k 了)。
  • 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"
redis-cli 對集群的支持是非常基本的, 所以它總是依靠 Redis 集群節點來將它轉向(redirect)至正確的節點。

一個真正的(serious)集群客戶端應該做得比這更好: 它應該用緩存記錄起哈希槽與節點地址之間的映射(map), 從而直接將命令發送到正確的節點上面。

這種映射只會在集群的配置出現某些修改時變化, 比如說, 在一次故障轉移(failover)之後, 或者系統管理員通過添加節點或移除節點來修改了集群的布局(layout)之後, 諸如此類。
轉自:http://www.redisdoc.com/en/latest/topic/cluster-tutorial.html
Copyright © Linux教程網 All Rights Reserved