上一篇文章描述了使用 Docker 基于哨兵模式搭建高可用的Redis,这一篇文章则使用Docker搭建Redis集群。
Redis Cluster 简介
Redis 3.0提供的分布式数据库解决方案——Redis Cluster。不仅可以主从复制,还可以像Sentinel那样有故障转移机制。除此之外,集群还有几个独有的特点:去中心化和数据分片。
去中心化:集群没有中心(核心)节点,就不会受到太大的影响,当某个主节点故障而不会影响整个集群的可用性。
分片:集群中的主节点可以水平扩展,使用哈希槽将键值对分配到不同的主节点,分担了单机Redis的压力。
接下来主要介绍如何使用 Docker 搭建Redis Cluster (Redis的版本为5.0)
1.创建集群目录,存放各个节点的配置目录(/conf/redis.conf)和数据目录(/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.获取各个容器的内外ip
for port in 'seq 8081 8089'; do echo -n "$(docker inspect --format '{{ (index .NetworkSettings.Networks "bridge").IPAddress }}' "redis-${port}")":${port} ' ' ; done
复制打印出来的ip和端口
4.创建集群
随便进入一个redis容器,譬如
docker exec -it redis-8081 /bin/bash
再执行创建集群的命令
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
这一条命令,表示集群中的每个主节点创建两个从节点。示例的集群为三主六从
显示 Can I set the above configuration? (type 'yes' to accept): 的时候,输入yes
如无意外的话,最后显示 [OK] All 16384 slots covered. 则代表集群创建成功!如果输入yes之后一直显示 Waiting for the cluster to join...
请参考我另外一篇拙作 搭建Redis集群遇到的问题:Waiting for the cluster to join...
执行cluster nodes
查看主从节点详细信息,如下图:
输出格式为:
<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
id
:节点 ID。一个40个字符的随机字符串,当一个节点被创建时不会再发生变化(除非CLUSTER RESET HARD被使用)。
ip:port
:客户端应该联系节点以运行查询的节点地址。
flags
:逗号列表分隔的标志:myself,master,slave,fail,handshake,noaddr,noflags。
master
:如果节点是从属节点,并且主节点已知,则节点ID为主节点,否则为“ - ”字符。
ping-sent
:以毫秒为单位的当前激活的ping发送的unix时间,如果没有挂起的ping,则为零。
pong-recv
:毫秒 unix 时间收到最后一个ping。
config-epoch
:当前节点(或当前主节点,如果该节点是从节点)的配置时期(或版本)。每次发生故障切换时,都会创建一个新的,唯一的,单调递增的配置时期。如果多个节点声称服务于相同的哈希槽,则具有较高配置时期的节点将获胜。
link-state
:用于节点到节点集群总线的链路状态。我们使用此链接与节点进行通信。可以是connected或disconnected。
slot
:散列槽号或范围。从参数9开始,但总共可能有16384个条目(限制从未达到)。这是此节点提供的散列槽列表。如果条目仅仅是一个数字,则被解析为这样。如果它是一个范围,它是在形式start-end,并且意味着节点负责所有散列时隙从start到end包括起始和结束值。
模拟主节点故障
模拟端口为8082的主节点发送故障,执行 docker stop redis-8082
后再次进入端口为8081的节点查看集群信息。可以看到端口为8082的节点的flag
标志为:master,fail;link-state
为disconnected。再看端口为8088的节点变为主节点,因此可以判断原先端口为8082的主节点下线后,故障转移由其从节点替代。
此时我再执行 docker start redis-8082
,可以发现端口为8082的服务在集群中connect,而且成为端口8088的从节点。
总结
以上就是使用Docker容器的技术搭建Redis集群,主要描述了Redis集群搭建的过程和模拟故障转移的实践。具体Redis命令背后的原理和详细的执行过程,推荐阅读黄健宏老师写的《Redis 设计与实现》,个人感觉写的十分通俗易懂,给了我很多启示!
参考资料:
https://cloud.tencent.com/developer/section/1374002
《Redis 设计与实现》