redis集羣的搭建與管理

一、redis集羣的搭建

1redis集羣中的數據分佈

(1)數據分區

    分佈式數據庫首先要解決把整個數據集按照分區規則映射到多個節點,每個節點負責整體數據的一個子集,常見的分區規則有哈希分區和順序分區兩種,常見的哈希分區規則有節點取餘分區、一致性哈希分區和虛擬槽分區。Redis cluster使用的爲哈希分區中的虛擬操分區。

(2)redis cluster數據分區

    Redis cluster採用虛擬槽分區,所有鍵根據哈希函數映射到0~16383整數槽內,計算公式爲:slot=CRC16(KEY)&16383,每個節點負責維護一部分槽以及槽所映射的鍵值數據。

(3)redis 虛擬槽分區的特點

    1)解耦數據和節點之間的關係,簡化了節點擴容和收縮難度

    2)節點自身維護槽的映射關係,不需要客戶端或者代理服務維護槽分區源數據

    3)支持節點、槽、鍵之間的映射查詢,用戶在線路由,數據伸縮等場景。

(4)redis cluster缺點

    1)key批量操作支持有限

    2)key事務的操作支持有限,同理只支持key在同一節點上的事務操作

    3)key作爲數據分區的最小粒度,因此不能將一個大的鍵值對象如hash、list等映射到不同的節點

    4)不支持多數據庫空間,集羣模式下只能使用一個數據庫空間。

    5)複製結構只支持一層,不支持嵌套樹狀複製結構。

2、集羣的搭建

(1)準備節點

    Redis cluster節點數量至少爲6個才能保證完成高可用性集羣,每個節點需要配置”cluster-enabled yes”。由於在每臺機器上起了兩個redis節點,需要爲每個節點統一規劃目錄,節點的準備如下:

角色

IP地址

端口

內存大小

備註

Redis master

192.168.16.128

6379

16g

主節點

Redis master

192.168.16.129

6379

16g

主節點

Redis master

192.168.16.130

6379

16g

主節點

Redis slave

192.168.16.128

6380

16g

16.129從節點

Redis slaver

192.168.16.129

6380

16g

16.130從節點

Redis slaver

192.168.16.130

6380

16g

16.128從節點

(2)節點的配置啓動

    Redis cluster相關的主要配置如下(各個節點根據節點的具體需求進行配置):

# 端口
port 6379
# 開啓集羣模式
cluster-enabled yes
# 集羣的內部配置文件
cluster-config-file nodes-6379.conf
# 節點的超時時間,單位毫秒
cluster-node-timeout 15000
# 數據存放目錄,不存在時需要創建,不然不能啓動
dir "/var/lib/redis/6379"
# 日誌存放文件
logfile "/var/log/redis/redis_6379.log"
# 運行時產生的pid文件存放目錄
pidfile "/var/run/redis_6380.pid"

    redis配置完成後,需要啓動所有的節點,由於是一個機器上部署了兩個redis實例,佔用了不同的端口;啓動時通過命令”redis-server /etc/redis/6379/6379.conf”來啓動

# 啓動192.168.16.128上的兩個redis
]# redis-server /etc/redis/6380/6380.conf
]# redis-server /etc/redis/6379/6379.conf
# 查看端口有沒有被監聽
]# ss -tanl | egrep "6379|6380"
LISTEN     0      128                       *:16379                    *:*     
LISTEN     0      128                       *:16380                    *:*     
LISTEN     0      128                       *:6379                     *:*     
LISTEN     0      128                       *:6380                     *:*  

    Redis cluster啓動成功後,如果沒有cluster的配置文件則會自動生成一份集羣的配置文件,存放在redis數據目錄下,當集羣內節點信息發生變化時,節點會自動保存集羣狀態到配置文件中。節點集羣配置文件中最最要的爲節點的ID,當各個節點啓動成功後,每個節點彼此不知道其他節點的存在,需要通過”握手”讓6個節點建立聯繫組成一個集羣。

(3)節點的握手

    節點握手是指一批運行在集羣模式下的節點通過Gossip協議彼此通信,達到感知對方的過程。節點握手時集羣彼此通信的第一步,只需要在集羣內的任意節點上執行”cluster meet {ip} {port}”命令加入新節點,握手消息會通過消息在集羣內傳播,這樣其他節點會自動發現新節點併發起握手流程。

# 執行meet命令讓所有的節點互相握手
127.0.0.1:6379> cluster meet 192.168.16.128 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.128 6380
OK
127.0.0.1:6379> cluster meet 192.168.16.129 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.129 6380
OK
127.0.0.1:6379> cluster meet 192.168.16.130 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.130 6380
OK
# 查看集羣的狀態
127.0.0.1:6379> cluster nodes
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.130:6380 master - 0 1535907782856 5 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535907781336 0 connected
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 master - 0 1535907783362 3 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 myself,master - 0 0 2 connected
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.130:6379 master - 0 1535907784374 4 connected
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 master - 0 1535907782346 1 connected

    節點握手後集羣還不能正常工作,只有將槽分配到對應的節點後集羣才能正常工作。

(4)分配槽

    節點握手完成後,需要爲節點分配槽,redis 集羣把所有的數據映射到16384個槽中,刻個key會映射一個固定的槽,只有當節點分配了槽,才能相應和槽關聯的命令,爲節點分配槽時通過”cluster addslots”命令完成的。

# 爲各主節點分配槽
]# redis-cli -h 192.168.16.128 -p 6379 cluster addslots {0..5461}
OK
]# redis-cli -h 192.168.16.129 -p 6379 cluster addslots {5462..10992}
OK
]# redis-cli -h 192.168.16.130 -p 6379 cluster addslots {10993..16282}
OK
# 分配完槽在查看節點狀態時,各節點獲取了相應的槽,集羣進入在線狀態
cluster nodes
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.133:6380 master - 0 1535908778762 5 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535908779266 0 connected 5462-10992
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 master - 0 1535908777752 3 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 myself,master - 0 0 2 connected 0-5461
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.133:6379 master - 0 1535908776737 4 connected 10993-16282
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 master - 0 1535908779774 1 connected

    再爲主節點分配完槽後,還需要使用”cluster replicate {nodeId}”命令爲每一個主節點分配一個從節點,該命令必須要在對應的從節點上執行,{nodId}爲要複製的主節點的id。

# 讓192.168.16.128:6380成爲192.168.16.129:6279的從節點
192.168.16.128:6380> cluster replicate faeed9b174f5506ca205cd5864806f0716c969c2
OK
# 讓192.168.16.129:6380成爲192.168.16.130:6279的從節點
192.168.16.129:6380> cluster replicate 174d5e01ff5fdaa5d10646483780afb34dd6b12b
OK
# 讓192.168.16.130:6380成爲192.168.16.128:6279的從節點
192.168.16.130:6380> cluster replicate ad864130ea5472462b3406563fdf14386465f7da
OK
# 再次查看節點狀態時各主節點都有了從節點
127.0.0.1:6380> cluster nodes
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 myself,slave faeed9b174f5506ca205cd5864806f0716c969c2 0 0 1 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535909496378 0 connected 5462-10992
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 slave 174d5e01ff5fdaa5d10646483780afb34dd6b12b 0 1535909495367 4 connected
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.133:6379 master - 0 1535909494358 4 connected 10993-16282
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.133:6380 slave ad864130ea5472462b3406563fdf14386465f7da 0 1535909493348 5 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 master - 0 1535909491828 2 connected 0-5461

3、使用redis-trib.rb快速搭建集羣

    當集羣內的節點數量多時,通過手動的方式搭建集羣費時費力,此時可通過redis-trib.rb來快速的搭建集羣。

    Redis-trib.rb是採用ruby實現的redis集羣管理工具,內部通過Cluster相關命令幫助我們簡化集羣創建、檢查、槽遷移和均衡等常見的操作;使用redis-trib.rb之前需要安裝ruby依賴環境。

(1)安裝前準備

    使用redis-trib.rb搭建集羣時由於機器有限將使用一臺新的機器,啓動6個redis實例完成集羣的搭建,各redis實例的安裝配置啓動同上面一樣。

角色

IP地址

端口

備註

Redis master

192.168.16.134

6379

各主從節點是隨機分配的,在生產中建議使用多臺機器,主從節點不會分配在同一臺機器上

Redis master

192.168.16.134

6380

Redis master

192.168.16.134

6381

Redis slave

192.168.16.134

6382

Redis slaver

192.168.16.134

6383

Redis slaver

192.168.16.134

6384

(2)安裝ruby及相關依賴

1)安裝ruby

# 下載安裝
# 安裝redis所需要的依賴
]# yum install zlib zlib-devel 
]# wget http://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.gz
]# tar -xf ruby-2.5.1.tar.gz 
]# cd ruby-2.5.1
]# ./configure --prefix=/usr/local/ruby
]# make && make install
# 建立快捷方式加入系統環境變量中或直接加環境變量
]# ln -s /usr/local/ruby/bin/ruby /usr/local/bin/
]# ln -s /usr/local/ruby/bin/gem /usr/local/bin/
         2)安裝redis-trib.rb

# 安裝redis插件,這一步安裝時有時會報錯,這次順利安裝
]# gem install redis
# 將redis源碼包下的” redis-trib.rb”拷貝到系統環境變量下
]# cp /usr/local/src/redis-3.2.12/src/redis-trib.rb /usr/local/bin/redis-trib.rb

    3)使用”redis-trib.rb”快速創建集羣

# 使用”redis-trib.rb快速創建集羣”
]# redis-trib.rb create --replicas 1 192.168.16.134:6379 192.168.16.134:6380 192.168.16.134:6381 192.168.16.134:6382 192.168.16.134:6383 192.168.16.134:6384

    4)查看集羣的狀態信息

    檢查集羣的狀態或查看集羣的信息通過任意一臺節點均可操作。操作命令分別如下:

        檢查集羣的狀態:redis-trib.rb check <nodeip>:<nodeport>

        查看集羣的信息:redis-trib.rb info <nodeip>:<nodeport>

# 檢查集羣的狀態
]# redis-trib.rb check 192.168.16.134:6379
>>> Performing Cluster Check (using node 192.168.16.134:6379)
M: 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 10aff3883025046ceba675d4272c7bdfd524a0c4 192.168.16.134:6384
   slots: (0 slots) slave
   replicates 333995e83ce190a5e6c52f8a7c216a9b73ef76ad
S: 3695a2eb1f7c10dcee7a3a61eccab57a296298c5 192.168.16.134:6382
   slots: (0 slots) slave
   replicates 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
S: a906637c42295a1f29b2eef1273a8a6c27f545d1 192.168.16.134:6383
   slots: (0 slots) slave
   replicates 8b3f2a2b393d593e4d33057223545a4308762858
M: 333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

4redis cluster節點通信

    Redis cluster各節點啓動後,會發現本地除了監聽配置文件中的端口外,還會監聽另一個redis節點監聽的端口加”10000”的端口,此端口主要用於各節點之間的通信。Redis各節點之間通信採用的是p2p的Gossip(流言)協議,Gossip協議工作的原理就是節點彼此不斷通信交換信息,一段時間後所有節點都會知道集羣的信息。

(1)Gossip消息的類型

    1)ping消息:用於檢測節點是否在線和交換彼此狀態信息

    2)meet消息:用於通知新節點的加入

    3)pong消息:當接收到ping、meet消息時,作爲響應消息回覆給發送方的確認消息

    4)fail消息:當節點判定集羣內一個節點下線時,會向集羣內廣播一個fail消息,其他節點接收到fail消息時把對應的節點更新爲下線狀態。

(2)通信節點的選擇

    集羣內每個節點維護定時任務默認每秒執行10次,每次會隨機選取5個節點找出最久沒有通信的節點發送ping消息,用於保證Gossip信息交換的隨機性。

二、redis集羣的管理

1、擴容集羣

    Redis集羣的擴容可以通過”準備節點”——>”讓節點加入集羣”——>”遷移槽和數據到新增節點”的流程完成集羣的擴容;遷移槽和數據到新節點過程手動操作時由於過程較多,容易出錯,這個過程可以通過”redis-trib”提供的槽重分片功能快速的完成槽的重新分片。

以下的操作均基於通過”redis-trib-rb”快速搭建的單機多實例的集羣中操作。

(1)準備新節點

角色

IP地址

端口

Redis master

192.168.16.134

6385

Redis master

192.168.16.134

6386

(2)讓節點加入集羣

# 讓新節點加入到集羣中
127.0.0.1:6379> CLUSTER MEET 192.168.16.134 6385
127.0.0.1:6379> CLUSTER MEET 192.168.16.134 6386
# 查看新添加節點狀態時由於沒有分配槽,還不能正常工作
127.0.0.1:6379> cluster nodes
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 192.168.16.134:6386 master - 0 1536001730850 0 connected
0bde7ccda11f686ffe3b5a2ad4020c282710018f 192.168.16.134:6385 master - 0 1536001727822 7 connected
……

    除了使用”cluster meet”命令讓節點加入集羣,還可以使用”redis-trib.rb”工具讓新增節點加入集羣,如果使用”redis-trib.rb”讓節點加入集羣,則執行的命令爲(在生產環境中建議使用”redis-trib.rb”命令加入新節點):

redis-trib.rb add-node 192.168.16.134:6385 192.168.16.134:6379
redis-trib.rb add-node 192.168.16.134:6385 192.168.16.134:6379

(3)手動遷移槽和數據

    在手動遷移槽和數據前需要爲新節點指定槽遷移計劃,確定原有槽的那些數據需要遷移到新節點;遷移計劃中要保證每個節點負責相似數量的槽,從而保證各節點數據的均勻。

    遷移的流程如下:

     1)對目標節點發送”cluster setslot {slot} importing {sourceNodeId}”命令,讓目標節點準備導入槽數據

    2)對源節點發送”cluster setslot {slot} migrating {targetNodeId}”命令,讓源節點準備遷出槽的數據。

    3)源節點循環執行”cluster getkeysinslot {slot} {count}”命令,獲取count個屬於{slot}的鍵

    4)在源節點上執行”migrate {targetIp} {gargetPort} “” 0 {timeout} keys {key…}”命令,把獲取到的鍵通過流水線(pipeline)機制批量遷移到目標節點;重複執行步驟3和4知道槽寫所有的鍵值數據都遷移到目標節點

    5)向集羣內的所有節點發送”cluster setslot {slot} node {targetNodeId}”命令,通知槽分配給目標節點。

(4)使用槽重分片功能”redis-trib”

    命令:redis-trib.rb reshard host:port –from <arg> --to <arg> --slots <arg> --yes –timeout <arg> --pipline <arg>

    參數:

       Host:port:集羣內任意幾點地址

       --from:指定源節點的Id,如果有多個源節點,使用逗號分隔

       --to:需要遷移的目標節點的id

       --slots:需要遷移槽的總數量,在遷移過程中提示用戶輸入,

       --yes:當打印出reshard執行計劃時,是否需要用戶輸入yes確認後在執行reshard

       --timeout:控制每次migrate操作的超時時間,默認爲60000毫秒

       --pipeline:控制每次遷移鍵的數量,默認爲10

# 使用redis-trib.rb完成數據的遷移和槽的重新分片
]# redis-trib.rb reshard 127.0.0.1:6379

    在遷移的過程中要求輸入遷移的槽的數量,目標節點的id(只能輸入一個),源節點的id(根據自己的集羣環境輸入,輸出完成後輸入”done”回車完成輸入)

# 遷移完成後查看新節點槽狀態,已經分配了槽,槽不連續不影響redis集羣的使用
127.0.0.1:6379> CLUSTER NODES
……
0bde7ccda11f686ffe3b5a2ad4020c282710018f 127.0.0.1:6385 master - 0 1536004597778 7 connected 0-1364 5461-6826 10923-12287

(5)爲新添加的主節點添加從節點

# 爲新增主節點添加從節點
192.168.16.134:6386> CLUSTER REPLICATE 0bde7ccda11f686ffe3b5a2ad4020c282710018f
# 查看節點狀態時從節點已經開始複製主節點
192.168.16.134:6386> cluster nodes
……
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 127.0.0.1:6386 myself,slave 0bde7ccda11f686ffe3b5a2ad4020c282710018f 0 0 0 connected

2、收縮集羣

    Redis集羣能夠擴容,也就能夠收縮,收縮redis集羣的流程與擴容redis集羣的流程恰恰相反。

(1)遷移下線節點負責的槽及數據

    在使用” redis-trib.rb reshard”命令遷移槽及數據到目標節點時,由於目標節點只能輸入一個,當有多個節點時需要執行多次” redis-trib.rb reshard”命令將要下線的節點的槽及數據遷移到其他節點。

    下線計劃:下線節點192.168.16.134:6379,將此節點負責的槽及數據遷移到其他的三個節點上。

# 查看節點192.168.16.134:6379負責的槽
127.0.0.1:6379> CLUSTER NODES
2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379 myself,master - 0 0 1 connected 1365-5460
# 遷移4095個槽到192.168.16.124:6380
]# redis-trib.rb reshard 192.168.16.134:6379
……
# 輸入遷移槽數量
How many slots do you want to move (from 1 to 16384)? 1365  
# 遷移到的目標節點192.168.16.134:6380的id
What is the receiving node ID? 8b3f2a2b393d593e4d33057223545a4308762858
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.
# 遷移到的源節點192.168.16.134:6379的id,輸入完成後輸入done結束
Source node #1:2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
Source node #2:done
……

    遷移完成後,按照上面的遷移方法,分別遷移1366、1365個槽到節點192.168.16.134:6381及節點192.168.16.134:6382。

# 遷移後的個主節點的槽分佈如下
127.0.0.1:6379> CLUSTER NODES
333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381 master - 0 1536006341658 9 connected 2730-4095 12288-16383
2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379 myself,master - 0 0 1 connected
8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380 master - 0 1536006345714 8 connected 1365-2729 6827-10922
0bde7ccda11f686ffe3b5a2ad4020c282710018f 127.0.0.1:6385 master - 0 1536006343700 10 connected 0-1364 4096-6826 10923-12287

(2)忘記節點

    槽遷移完成後,爲了讓其他節點不再與下線節點進行Gossip消息交換,需要讓集羣內的所有節點忘記要下線的幾點。

    命令:redis-trib.rb del-node {host:port} {downNodeId}

# 讓所有幾點忘記下線的節點192.168.16.134:6379及它的從節點192.168.16.134:6379:6382
]# redis-trib.rb del-node 192.168.16.134:6379 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
>>> Removing node 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 from cluster 192.168.16.134:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
]# redis-trib.rb del-node 192.168.16.134:6382 3695a2eb1f7c10dcee7a3a61eccab57a296298c5

    忘記節點後再次查看節點狀態時,集羣中已經沒有下線節點192.168.16.134:6379及節點192.168.16.134:6382的信息。

192.168.16.134:6380> CLUSTER NODES
0bde7ccda11f686ffe3b5a2ad4020c282710018f 192.168.16.134:6385 master - 0 1536006923917 10 connected 0-1364 4096-6826 10923-12287
a906637c42295a1f29b2eef1273a8a6c27f545d1 192.168.16.134:6383 slave 8b3f2a2b393d593e4d33057223545a4308762858 0 1536006921379 8 connected
8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380 myself,master - 0 0 8 connected 1365-2729 6827-10922
333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381 master - 0 1536006926953 9 connected 2730-4095 12288-16383
10aff3883025046ceba675d4272c7bdfd524a0c4 192.168.16.134:6384 slave 333995e83ce190a5e6c52f8a7c216a9b73ef76ad 0 1536006924931 9 connected
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 127.0.0.1:6386 slave 0bde7ccda11f686ffe3b5a2ad4020c282710018f 0 1536006925939 10 connected

3、連接集羣

(1)連接重定向

    Redis在集羣模式下接受任何鍵相關命令時首先計算鍵對應的槽,再根據槽找出所對應的節點,如果節點時自身則處理請求命令,否則恢復move重定向錯誤,通知客戶端請求正確的節點。如果在使用”redis-cli”命令時加”-c”參數則會自動重定向。

(2)程序連接redis

    smart客戶端支持集羣協議。

三、redis集羣故障的發現與恢復

1、故障的發現

(1)主觀下線(pfail)

    某個節點認爲一個節點不可用

(2)客觀下線(fail)

    集羣內多個節點都認爲某個節點不可用,從而達成共識標識該節點下線;如果該節點爲主節點則要進行故障轉移

2、故障恢復

    故障節點變爲客觀下線後,如果下線節點時持有槽的主節點,則需要在它的從節點中選舉出一個替換它。選舉流程如下

(1)資格檢查

(2)準備選舉時間

(3)發起選舉

(4)選舉投票

(5)替換主節點

3、手動故障轉移

    Redis支持手動故障轉移功能,指定從節點發起故障轉移流程,主從節點進行故障的切換。

   手動故障轉移命令:cluster failover

 

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