上一篇文章描述了使用 Docker 基于哨兵模式搭建高可用的Redis,這一篇文章則使用Docker搭建Redis集群。
Redis Cluster 簡介
Redis 3.0提供的分布式數(shù)據(jù)庫解決方案——Redis Cluster。不僅可以主從復制,還可以像Sentinel那樣有故障轉(zhuǎn)移機制。除此之外,集群還有幾個獨有的特點:去中心化和數(shù)據(jù)分片。
去中心化:集群沒有中心(核心)節(jié)點,就不會受到太大的影響,當某個主節(jié)點故障而不會影響整個集群的可用性。
分片:集群中的主節(jié)點可以水平擴展,使用哈希槽將鍵值對分配到不同的主節(jié)點,分擔了單機Redis的壓力。
接下來主要介紹如何使用 Docker 搭建Redis Cluster (Redis的版本為5.0)
1.創(chuàng)建集群目錄,存放各個節(jié)點的配置目錄(/conf/redis.conf)和數(shù)據(jù)目錄(/data)
for port in 'seq 8081 8089' ; do mkdir -p ./${port}/conf && PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf && mkdir -p ./${port}/data; done
2.運行端口為8081~8089的容器
for port in 'seq 8081 8089'; do docker run -d -ti -p ${port}:${port} -p 1${port}:1${port} -v /cluster-docker/${port}/conf/redis.conf:/etc/redis/redis.conf -v /cluster-docker/${port}/data:/data --restart always --name redis-${port} --net redis-net --sysctl net.core.somaxconn=1024 redis:5.0 redis-server /etc/redis/redis.conf; done

3.獲取各個容器的內(nèi)外ip
for port in 'seq 8081 8089'; do echo -n "$(docker inspect --format '{{ (index .NetworkSettings.Networks "bridge").IPAddress }}' "redis-${port}")":${port} ' ' ; done
復制打印出來的ip和端口
4.創(chuàng)建集群
隨便進入一個redis容器,譬如
docker exec -it redis-8081 /bin/bash
再執(zhí)行創(chuàng)建集群的命令
redis-cli --cluster create 172.17.0.2:8081 172.17.0.3:8082 172.17.0.4:8083 172.17.0.5:8084 172.17.0.6:8085 172.17.0.7:8086 172.17.0.8:8087 172.17.0.9:8088 172.17.0.10:8089 --cluster-replicas 2
需要特別說明的是 --cluster-replicas 2 這一條命令,表示集群中的每個主節(jié)點創(chuàng)建兩個從節(jié)點。示例的集群為三主六從

顯示 Can I set the above configuration? (type 'yes' to accept): 的時候,輸入yes
如無意外的話,最后顯示 [OK] All 16384 slots covered. 則代表集群創(chuàng)建成功!如果輸入yes之后一直顯示 Waiting for the cluster to join... 請參考我另外一篇拙作 搭建Redis集群遇到的問題:Waiting for the cluster to join...

執(zhí)行cluster nodes查看主從節(jié)點詳細信息,如下圖:

輸出格式為:
<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
id:節(jié)點 ID。一個40個字符的隨機字符串,當一個節(jié)點被創(chuàng)建時不會再發(fā)生變化(除非CLUSTER RESET HARD被使用)。
ip:port:客戶端應該聯(lián)系節(jié)點以運行查詢的節(jié)點地址。
flags:逗號列表分隔的標志:myself,master,slave,fail,handshake,noaddr,noflags。
master:如果節(jié)點是從屬節(jié)點,并且主節(jié)點已知,則節(jié)點ID為主節(jié)點,否則為“ - ”字符。
ping-sent:以毫秒為單位的當前激活的ping發(fā)送的unix時間,如果沒有掛起的ping,則為零。
pong-recv:毫秒 unix 時間收到最后一個ping。
config-epoch:當前節(jié)點(或當前主節(jié)點,如果該節(jié)點是從節(jié)點)的配置時期(或版本)。每次發(fā)生故障切換時,都會創(chuàng)建一個新的,唯一的,單調(diào)遞增的配置時期。如果多個節(jié)點聲稱服務于相同的哈希槽,則具有較高配置時期的節(jié)點將獲勝。
link-state:用于節(jié)點到節(jié)點集群總線的鏈路狀態(tài)。我們使用此鏈接與節(jié)點進行通信??梢允莄onnected或disconnected。
slot:散列槽號或范圍。從參數(shù)9開始,但總共可能有16384個條目(限制從未達到)。這是此節(jié)點提供的散列槽列表。如果條目僅僅是一個數(shù)字,則被解析為這樣。如果它是一個范圍,它是在形式start-end,并且意味著節(jié)點負責所有散列時隙從start到end包括起始和結(jié)束值。
模擬主節(jié)點故障
模擬端口為8082的主節(jié)點發(fā)送故障,執(zhí)行 docker stop redis-8082 后再次進入端口為8081的節(jié)點查看集群信息。可以看到端口為8082的節(jié)點的flag 標志為:master,fail;link-state 為disconnected。再看端口為8088的節(jié)點變?yōu)橹鞴?jié)點,因此可以判斷原先端口為8082的主節(jié)點下線后,故障轉(zhuǎn)移由其從節(jié)點替代。

此時我再執(zhí)行 docker start redis-8082 ,可以發(fā)現(xiàn)端口為8082的服務在集群中connect,而且成為端口8088的從節(jié)點。

總結(jié)
以上就是使用Docker容器的技術(shù)搭建Redis集群,主要描述了Redis集群搭建的過程和模擬故障轉(zhuǎn)移的實踐。具體Redis命令背后的原理和詳細的執(zhí)行過程,推薦閱讀黃健宏老師寫的《Redis 設(shè)計與實現(xiàn)》,個人感覺寫的十分通俗易懂,給了我很多啟示!
參考資料:
https://cloud.tencent.com/developer/section/1374002
《Redis 設(shè)計與實現(xiàn)》