集群搭建概述
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