redis集羣的搭建

redis集羣的搭建

本文使用的是3臺主機,每臺主機2個節點,3臺maser,3臺salve的環境。

1. 環境介紹:

3臺CentOS release 6.9服務器

  192.168.1.35
  192.168.1.36
  192.168.1.37

redis-4.0.9.tar.gz 
ruby-2.4.4.tar.gz

2. 軟件安裝

安裝redis:

本文中的環境默認是不能連接外網的。所以軟件包只能通過跳板機或者其他的機器通過scp上傳。 
編譯安裝:

tar -xf redis-4.0.9.tar.gz 
mkdir -p /usr/local/redis    
mv redis-4.0.9/* /usr/local/redis/
cd /usr/local/redis/
make && make install

創建redis節點:

mkdir -p redis_cluster/{7000,7001}
cp redis.conf redis_cluster/7000
cp redis.conf resis_cluster/7001

分別修改7000/7001裏面的配置文件的內容:

port 7000           //端口7000,7001
bind  192.168.1.35  //改爲35,36,37
daemonize yes     //redis後臺運行
pidfile /var/run/redis_7000.pid     //pid對應7000,7001
cluster-enabled yes   //開啓集羣
cluster-config-file  nodes_7000.conf   //指定集羣的配置文件,自動生成
cluster-node-timeout 15000  //設置集羣超時時間
appendonly  yes        //aof日誌開啓,它會每次寫操作都記錄一條日誌

在另外的兩臺機器上重複上面的配置規則 
啓動各個節點(另外兩臺也是同樣地): 
redis-server redis_cluster/7000/redis.conf 
redis-server redis_cluster/7001/redis.conf

查看各個節點是否起來:
$ ss -tnlp|grep redis
 LISTEN 0 511 192.168.1.35:17000 *:* users:(("redis-server",24909,9))
 LISTEN 0 511 192.168.1.35:17001 *:* users:(("redis-server",24914,9))
 LISTEN 0 511 192.168.1.35:7000 *:* users:(("redis-server",24909,6))
 LISTEN 0 511 192.168.1.35:7001 *:* users:(("redis-server",24914,6))

安裝ruby:

tar -xf  ruby-2.4.4.tar.gz 
cd ruby-2.4.4
./configure --prefix=/usr/local/ruby
make && make install 
 /usr/local/ruby/bin/gem install redis

或者

安裝gem和redis的插件(https://rubygems.global.ssl.fastly.net/gems/redis-3.2.2.gem)
# gem install -l redis-3.2.2.gem

3. 集羣創建

redis-trib.rb是redis官方推出的redis集羣管理的工具,這個工具在redis的src目錄下。

/usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb create --replicas 1 192.168.1.35:7000 192.168.1.35:7001 192.168.1.36:7000 192.168.1.36:70001 192.168.1.37:7000 192.168.1.37:7001

--replicas:指定每個主節點有幾個從節點
注意:需要有3個或者以上的主節點,否則在創建集羣是會失敗,並且存活的主節點數小於總節點數的一半時,整個集羣就無法提供服務了。
原理:redis cluster在設計的時候,就考慮到了去中心化去中間件,就是說,集羣中的每個節點都是平等的關係,都是對等的,每個節點都保存各自的數據和整個集羣的狀態。每個節點都和其他所有節點連接,而且這些連接保持活躍,這樣就保證了我們只需要連接集羣中的任意一個節點,就可以獲取到其他節點的數據。  Redis 集羣沒有並使用傳統的一致性哈希來分配數據,而是採用另外一種叫做哈希槽 (hash slot)的方式來分配的。redis cluster 默認分配了 16384 個slot,當我們set一個key 時,會用CRC16算法來取模得到所屬的slot,然後將這個key 分到哈希槽區間的節點上,具體算法就是:CRC16(key) % 16384。所以我們在測試的時候看到set 和 get 的時候,直接跳轉到了7000端口的節點。  Redis 集羣會把數據存在一個 master 節點,然後在這個 master 和其對應的salve 之間進行數據同步。當讀取數據時,也根據一致性哈希算法到對應的 master 節點獲取數據。只有當一個master 掛掉之後,纔會啓動一個對應的 salve 節點,充當 master 。

4.集羣驗證:

可以通過隨便在一臺機器上創建數據來驗證整個集羣。

通過redis-cli命令來登陸
$ redis-cli -h 192.168.1.35 -c -p 7000
192.168.1.37:7000> set hello world
-> Redirected to slot [866] located at 192.168.1.35:7000
OK
192.168.1.35:7000> keys *
1) "hello"

然後登陸另外一臺的7000端口,查看key的內容。

$ redis-cli -h 192.168.1.36 -c -p 7000
192.168.1..36:7000> get hello
-> Redirected to slot [866] located at 192.168.1.35:7000
"world"
192.168.1.35:7000>

如果其他節點可以讀取得到就說明集羣運行正常。

5.redis集羣管理工具redis-trib.rb

redis-trib.rb是redis官方推出的管理redis集羣的工具,集成在redis的源碼src目錄下,是基於redis提供的集羣命令封裝成簡單、便捷、實用的操作工具。 
redis-trib.rb的功能參數:

Usage: redis-trib <command> <options> <arguments ...>
  create host1:port1 ... hostN:portN
              --replicas <arg>
  check host:port
  info host:port
  fix host:port
                  --timeout <arg>
  reshard host:port
                  --from <arg>
                  --to <arg>
                  --slots <arg>
                  --yes
                  --timeout <arg>
                  --pipeline <arg>
  rebalance host:port
                  --weight <arg>
                  --auto-weights
                  --use-empty-masters
                  --timeout <arg>
                  --simulate
                  --pipeline <arg>
                  --threshold <arg>
  add-node new_host:new_port existing_host:existing_port
                  --slave
                  --master-id <arg>
  del-node host:port node_id
  set-timeout host:port milliseconds
  call host:port command arg arg .. arg
  import host:port
                  --from <arg>
                  --copy
                  --replace
  help (show this help)
    For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node     in   the cluster.

簡單來看:redis-trib.rb提供了以下的功能:

create創建集羣
check檢查集羣
info查看集羣信息
fix修復集羣
reshard在線遷移集羣
rebalance平衡集羣節點的slot數量
add-node將節點加入新的集羣
del-node從集羣中刪除節點
set-timout設置集羣節點間的心跳連接超時時間
call在集羣全部節點上執行命令
import將外部的redis數據導入集羣

create創建集羣:

可選參數爲replicas,表示需要幾個slave。 
簡單用法:

ruby redis-trib.rb create 192.168.1.20:7000 192.168.1.21:7000 192.168.1.22:7000

有一個從節點的創建命令:

ruby redis-trib.rb create  --replicas 1 192.168.1.20:7000 192.168.1.21:7000 192.168.1.22:7000 192.168.1.23:7000 192.168.1.24:7000 192.168.1.25:7000

創建流程如下: 
1、首先爲每個節點創建ClusterNode對象,包括連接每個節點。檢查每個節點是否爲獨立且db爲空的節點。執行load_info方法導入節點信息。 
2、檢查傳入的master節點數量是否大於等於3個。只有大於3個節點才能組成集羣。 
3、計算每個master需要分配的slot數量,以及給master分配slave。分配的算法大致如下: 先把節點按照host分類,這樣保證master節點能分配到更多的主機中。 不停遍歷遍歷host列表,從每個host列表中彈出一個節點,放入interleaved數組。直到所有的節點都彈出爲止。 master節點列表就是interleaved前面的master數量的節點列表。保存在masters數組。 計算每個master節點負責的slot數量,保存在slots_per_node對象,用slot總數除以master數量取整即可。 遍歷masters數組,每個master分配slots_per_node個slot,最後一個master,分配到16384個slot爲止。 接下來爲master分配slave,分配算法會盡量保證master和slave節點不在同一臺主機上。對於分配完指定slave數量的節點,還有多餘的節點,也會爲這些節點尋找master。分配算法會遍歷兩次masters數組。 第一次遍歷masters數組,在餘下的節點列表找到replicas數量個slave。每個slave爲第一個和master節點host不一樣的節點,如果沒有不一樣的節點,則直接取出餘下列表的第一個節點。 第二次遍歷是在對於節點數除以replicas不爲整數,則會多餘一部分節點。遍歷的方式跟第一次一樣,只是第一次會一次性給master分配replicas數量個slave,而第二次遍歷只分配一個,直到餘下的節點被全部分配出去。 
4、打印出分配信息,並提示用戶輸入“yes”確認是否按照打印出來的分配方式創建集羣。 
5、輸入“yes”後,會執行flush_nodes_config操作,該操作執行前面的分配結果,給master分配slot,讓slave複製master,對於還沒有握手(cluster meet)的節點,slave複製操作無法完成,不過沒關係,flush_nodes_config操作出現異常會很快返回,後續握手後會再次執行flush_nodes_config。 
6、給每個節點分配epoch,遍歷節點,每個節點分配的epoch比之前節點大1。 
7、節點間開始相互握手,握手的方式爲節點列表的其他節點跟第一個節點握手。 
8、然後每隔1秒檢查一次各個節點是否已經消息同步完成,使用ClusterNode的get_config_signature方法,檢查的算法爲獲取每個節點cluster nodes信息,排序每個節點,組裝成node_id1:slots|node_id2:slot2|...的字符串。如果每個節點獲得字符串都相同,即認爲握手成功。 
9、此後會再執行一次flush_nodes_config,這次主要是爲了完成slave複製操作。 
10、最後再執行check_cluster,全面檢查一次集羣狀態。包括和前面握手時檢查一樣的方式再檢查一遍。確認沒有遷移的節點。確認所有的slot都被分配出去了。 
11、至此完成了整個創建流程,返回[OK]

check檢查集羣

使用check來檢查集羣的狀態。只需要選擇其中的一個節點即可:

$ /usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb check 192.168.1.36:7000
>>> Performing Cluster Check (using node 192.168.1.36:7000)
M: 631e3b56a0895f5ac62b15ad7467752877d8079e 1192.168.1.36:7000
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: d35e7bd3a31054b96dfe2d08d7472731753d6ceb 192.168.1.37:7000
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 06fbb8062252b78093d4ef50188199a580bb86bd 192.168.1.35:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 4e26eac416d32421800f91f78a9df070aa7d0855 192.168.1.35:7001
   slots: (0 slots) slave
   replicates d35e7bd3a31054b96dfe2d08d7472731753d6ceb
S: 8090354b1b3575ae1e331841964c6c33c55897da 192.168.1.37:7001
   slots: (0 slots) slave
   replicates 631e3b56a0895f5ac62b15ad7467752877d8079e
S: 0909bb82f88e0755bab3bc06f1cc3b4325c2a869 192.168.1.36:7001
   slots: (0 slots) slave
   replicates 06fbb8062252b78093d4ef50188199a580bb86bd
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

info查看集羣的信息

info命令用來查看集羣的信息,同樣只需要指定一個節點即可:

/usr/local/ruby/bin/ruby /usr/local/redis/src/redis-trib.rb info 192.168.1.36:7000
192.168.1.36:7000 (631e3b56...) -> 1 keys | 5462 slots | 1 slaves.
192.168.1.37:7000 (d35e7bd3...) -> 0 keys | 5461 slots | 1 slaves.
192.168.1.35:7000 (06fbb806...) -> 1 keys | 5461 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0.00 keys per slot on average.

fix修復集羣:

fix命令的流程跟check的流程很像,顯示加載集羣信息,然後在check_cluster方法內傳入fix爲 true的變量,會在集羣檢查出現異常的時候執行修復流程。目前fix命令能修復兩種異常,一種是集羣有處於遷移中的slot的節點,一種是slot未完全分配的異常。 
fix_open_slot方法是修復集羣有處於遷移中的slot的節點異常: 
1、先檢查該slot是誰負責的,遷移的源節點如果沒完成遷移,owner還是該節點。沒有owner的slot無法完成修復功能。 
2、遍歷每個節點,獲取哪些節點標記該slot爲migrating狀態,哪些節點標記該slot爲importing狀態。對於owner不是該節點,但是通過cluster countkeysinslot獲取到該節點有數據的情況,也認爲該節點爲importing狀態。 
3、如果migrating和importing狀態的節點均只有1個,這可能是遷移過程中redis-trib.rb被中斷所致,直接執行move_slot繼續完成遷移任務即可。傳遞dots和fix爲true。 
4、如果migrating爲空,importing狀態的節點大於0,那麼這種情況執行回滾流程,將importing狀態的節點數據通過move_slot方法導給slot的owner節點,傳遞dots、fix和cold爲true。接着對importing的節點執行cluster stable命令恢復穩定。 
5、如果importing狀態的節點爲空,有一個migrating狀態的節點,而且該節點在當前slot沒有數據,那麼可以直接把這個slot設爲stable。 
6、如果migrating和importing狀態不是上述情況,目前redis-trib.rb工具無法修復,上述的三種情況也已經覆蓋了通過redis-trib.rb工具遷移出現異常的各個方面,人爲的異常情形太多,很難考慮完全。 fix_slots_coverage方法能修復slot未完全分配的異常: 
未分配的slot有三種狀態: 
1、所有節點的該slot都沒有數據。該狀態redis-trib.rb工具直接採用隨機分配的方式,並沒有考慮節點的均衡。本人嘗試對沒有分配slot的集羣通過fix修復集羣,結果slot還是能比較平均的分配,但是沒有了連續性,打印的slot信息非常離散。 
2、有一個節點的該slot有數據。該狀態下,直接把slot分配給該slot有數據的節點。 
3、有多個節點的該slot有數據。此種情況目前還處於TODO狀態,不過redis作者列出了修復的步驟,對這些節點,除第一個節點,執行cluster migrating命令,然後把這些節點的數據遷移到第一個節點上。清除migrating狀態,然後把slot分配給第一個節點。

reshard在線遷移slot:

reshard命令可以在線把集羣的一些slot從集羣原來slot負責節點遷移到新的節點,利用reshard可以完成集羣的在線橫向擴容和縮容。 
reshard的參數介紹:

reshard        host:port   指定從哪個節點獲取集羣的信息
                     --from        需要從哪些節點上遷移slot。--from all 所有節點
                     --to        slot需要遷移的目的節點node id
                     --slots    需要遷移的slot數量
                     --yes    設置該參數,會提示輸入yes後再執行reshard
                     --timeout  設置migrate命令的超時時間
                     --pipeline    定義cluster getkeysinslot一次取出的key數量,默認爲10

參考文獻 
redis集羣教程 
redis集羣規範 
https://redis.io/topics/cluster-spec 
https://redis.io/topics/cluster-tutorial


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