docker-compose搭建redis叢集及可用性實踐
叢集搭建概述
redis一般需要6個節點才能組成完整的高可用叢集,這裡我們使用docker-compose
來快速搭建叢集。
叢集搭建一般分為三個步驟:
- 準備節點
- 節點握手
- 分配槽
步驟一:準備節點
從GitHub下載程式碼
專案GitHub地址:github.com/willcat/red…
注意
由於程式碼更新,在配置檔案中手動設定了容器名稱,所以文章和程式碼中的容器名有區別,比如文章中的redis-cluster_redis-cluster-6380_1
,在程式碼和實際執行中是node-80
,文章中的redis-cluster_redis-cluster-6381_1
,在程式碼和實際執行中是node-81
開啟後臺服務,啟動所有節點
進入redis-cluster-docker目錄,執行docker-compose up -d
檢查當前叢集狀況
隨便進入一個容器比如redis-cluster_redis-cluster-6380_1
[1],docker exec -it redis-cluster_redis-cluster-6380_1 redis-cli -p 6380
,然後執行cluster nodes
命令,整個過程如下:
$ docker exec -it redis-cluster_redis-cluster-6380_1 redis-cli -p 6380
127.0.0.1:6380> cluster nodes
3914fe7597f9ad9e9c485cf473bcaa461973baaa :6380@16380 myself,master - 0 0 0 connected
複製程式碼
可以看到目前各個節點還只能返回自己的資訊,每個節點還不能感知到彼此。
[1] 這是docker-compose
根據我們在docker-compose.yml
配置的服務名稱自動生成的,如果不想使用預設名稱,可以在配置檔案中使用container_name
指定容器名稱
docker exec
步驟二 節點握手
節點握手是指一批執行在叢集模式下的節點通過Gossip
協議彼此通訊,達到感知對方的過程。
- 在某個節點上執行
cluster meet {ip} {port}
命令,達到兩個節點間的握手,這兩個節點就組成了一個真正的彼此感知的叢集,之後兩個節點間會定期通過ping/pong
訊息進行正常的節點通訊 - 在叢集中任意節點上執行
cluster meet {ip} {port}
命令,新增尚未加入叢集的新節點 - 所有節點全部加入之後可以看到叢集中所有節點資訊
127.0.0.1:6380> cluster nodes
c6db83c252a072407707917474001c70da649407 172.26.0.6:6385@16385 master - 0 1565199856348 3 connected
e356c336482f7a8a3f786674b96ac06030b0dcb4 172.26.0.3:6381@16381 master - 0 1565199855000 0 connected
dae83c485b9fb1357947944b36007c3371a750f2 172.26.0.7:6383@16383 master - 0 1565199857362 5 connected
c87aba899473356f25a919dc2d477340f5222ba4 172.26.0.2:6382@16382 master - 0 1565199855000 4 connected
5ebbd85dfbe1e4e01bae5f4954418a436453876c 172.26.0.5:6384@16384 master - 0 1565199855339 2 connected
3914fe7597f9ad9e9c485cf473bcaa461973baaa 172.26.0.4:6380@16380 myself,master - 0 1565199855000 1 connected
複製程式碼
補充知識:docker-compose預設組網
- 使用docker-compose up啟動容器後,這些容器都會被加入
{app_name}_default
網路中 - 使用
docker network ls
可以檢視網路列表,docker network inspect <network_name>
可以檢視對應網路的配置以及各個容器的ip。 - 還可以通過
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-cluster_redis-cluster-6385_1
命令直接檢視某個容器的ip。
步驟三 分配槽
節點建立握手之後,叢集還處於下線狀態,無法執行寫操作。
127.0.0.1:6380> set hello world
(error) CLUSTERDOWN Hash slot not served
複製程式碼
檢視叢集資訊可以看到叢集是fail
狀態
127.0.0.1:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:718
cluster_stats_messages_pong_sent:283
cluster_stats_messages_meet_sent:8
cluster_stats_messages_sent:1009
cluster_stats_messages_ping_received:283
cluster_stats_messages_pong_received:285
cluster_stats_messages_received:568
複製程式碼
執行分配槽的命令
在各個節點上執行類似cluster addslots {0...5461}
的命令,將0~16383個slot平均分配到所有節點上。這裡我們只分配三個節點,另外三個節點分別當作前面三個節點的從節點,從而在主節點出現故障時能夠自動完成故障轉移。
//分配三個節點,注意,以下三個命令在登入redis-cli之後是不成功的,只能使用redis-cli -p 6380 cluster addslots {0..5461}這種模式
$ docker exec -it redis-cluster_redis-cluster-6380_1 redis-cli -p 6380 cluster addslots {0..5461}
$ docker exec -it redis-cluster_redis-cluster-6381_1 redis-cli -p 6381 cluster addslots {5462..10922}
$ docker exec -it redis-cluster_redis-cluster-6382_1 redis-cli -p 6382 cluster addslots {10923..16282}
// 將三個未分配槽的節點設定為從節點
127.0.0.1:6383> CLUSTER REPLICATE 3914fe7597f9ad9e9c485cf473bcaa461973baaa
OK
127.0.0.1:6384> CLUSTER REPLICATE e356c336482f7a8a3f786674b96ac06030b0dcb4
OK
127.0.0.1:6385> CLUSTER REPLICATE c87aba899473356f25a919dc2d477340f5222ba4
OK
複製程式碼
官方叢集快速搭建工具
這樣3主3從的叢集就搭建完成了,可以感覺到還是比較麻煩的,所以redis官方在redis3.x
和redis4.x
提供了redis-trib.rb
工具方便我們快速搭建叢集,在redis5.x
中更是可以直接使用redis-cli
命令來直接完成叢集的一鍵搭建,省去了redis-trib.rb
依賴ruby環境的問題。在程式碼中,readme.md裡提供了快速搭建的命令。
//官方指出: 可以使用redis5.x 的redis-cli命令模式來搭建由redis-4.x組成的叢集。
redis-cli --cluster create 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 \
--cluster-replicas 1
複製程式碼
叢集使用
請求重定向
在叢集中某個節點讀寫不屬於此節點的資料會返回錯誤(error) MOVED 5798 172.20.0.6:6381
,為了減少手動切換的環節,在開啟客戶端時可以新增-c
引數,開啟請求重定向,詳細命令redis-cli -p 6380 -c
,這樣以後操作跨節點時會自動跳轉到相應的節點
Smart客戶端
大多數開發語言的Redis客戶端都採用Smart客戶端支援叢集協議,客戶端選擇可以參考clients。
- Smart客戶端在內容維護slot->node的對映關係,本地就可實現鍵到節點的查詢,從而保證IO效率的最大化
- 而
Moved
重定向負責協助Smart客戶端更新slot->node的對映關係。
ASK重定向
當叢集伸縮時,slot會發生遷移,這時去原來節點讀寫會返回(error) ASK {slot} {targetIP}:{targetPort}
錯誤,客戶端從ASK重定向異常提取出目標節點資訊,傳送asking
命令到目標節點開啟客戶端連線標識,再執行鍵命令。如果存在則執行,不存在則返回不存在資訊。
叢集容錯
TODO