背景:Redis的官方多机部署方案,Redis Cluster。一组Redis Cluster是由多个Redis实例组成,官方推荐我们使用6实例,其中3个为主节点,3个为从结点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从结点成为新的主节点,继续对外服务,从而保证服务的高可用性。那么对于客户端来说,知道对应的key是要路由到哪一个节点呢?原来,Redis Cluster 把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部门的Redis数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。
1、本文使用一台物理机,用docker部署多个redis
1.1、创建一个docker虚拟网卡
# 创建redis-cluster虚拟网卡
docker network create redis-cluster
1.2、修改redis.conf,依次修改6个redis的redis.conf,其他redis的配置类似,示例如下
# port(不同的redis对应各自的端口)
port 7379
# 支持集群模式
cluster-enabled yes
# 集群配置名 例nodes-7379.conf
cluster-config-file nodes-port.conf
# 超时时间
cluster-node-timeout 5000
# 实际上各个网卡的ip(此字段一定要添加)
cluster-announce-ip 192.168.8.124
# 节点映射端口(不同的redis对应各自的端口)
cluster-announce-port 7379
# 节点总线端(不同的redis对应各自的端口)
cluster-announce-bus-port 17379
# 持久化模式打开
appendonly yes
# 保护模式关闭
protected-mode no
1.3、redis启动脚本restart.sh, redis的port和cluster-announce-bus-port一定要挂载出来,不同的redis修改不同的端口映射
# BEGIN ANSIBLE MANAGED BLOCK
#!/bin/bash
HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker rm -f redis_4.0.10_7379;
docker run --network redis-cluster --name redis_4.0.10_7379 \
--restart=always \
-v $HOME/data:/data \
-v $HOME/redis:/etc/redis \
-p 7379:7379 \
-p 17379:17379 \
-d redis:4.0.10 \
redis-server /etc/redis/redis.conf --appendonly yes
# END ANSIBLE MANAGED BLOCK
- redis cluster需要6个节点,依次修改上述脚本,创建redis_4.0.10_7379、redis_4.0.10_7479、redis_4.0.10_7579、redis_4.0.10_7679、redis_4.0.10_7779、redis_4.0.10_7879
-
此时6个redis已经创建完毕(如下图)
2、redis集群创建
2.1、5.0.0以后版本
- 进入到任一节点,执行脚本即可,集群即可创建成功
# 创建redis集群 -a ds123 -a 后面跟的redis密码
redis-cli -a 123456 --cluster create --replicas 1 192.168.8.124:7379 192.168.8.124:7479 192.168.8.124:7579 192.168.8.124:7679 192.168.8.124:7779 192.168.8.124:7879
2.2、5.0.0以前版本
由于redis还不支持--cluster参数,只能先安装ruby环境,然后进行集群创建
2.2.1、安装ruby环境
-
目录文件如下
- redis-trib.rb 是从安装的redis包中拷贝出来的,一般在src目录下
2.2.2、创建镜像
- Dockerfile 如下
FROM ruby:latest
MAINTAINER lss
RUN gem install redis
RUN mkdir /redis
WORKDIR /redis
ADD ./redis-trib.rb /redis/redis-trib.rb
# 根据Dockerfile创建镜像
docker build -t redis-trib .
2.2.3、restart.sh
# BEGIN ANSIBLE MANAGED BLOCK
#!/bin/bash
HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker rm -f redis-trib;
docker run -dit --network redis-cluster --name redis-trib \
redis-trib:latest \
# END ANSIBLE MANAGED BLOCK
2.2.4、进入到redis-trib容器中,创建集群
# 进入容器
docker exec -it redis-trib bash
# 创建6个节点
ruby redis-trib.rb create --replicas 1 192.168.8.124:7379 192.168.8.124:7479 192.168.8.124:7579 192.168.8.124:7679 192.168.8.124:7779 192.168.8.124:7879
-
日志如下
说明集群创建成功
3、集群测试
- 进入任一redis节点中
# 进入7379节点
redis-cli -p 7379 -c
# 查看集群信息
127.0.0.1:7379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:388
cluster_stats_messages_pong_sent:405
cluster_stats_messages_sent:793
cluster_stats_messages_ping_received:400
cluster_stats_messages_pong_received:388
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:793
# 查看集群节点
127.0.0.1:7379> cluster nodes
f845f1dfed78a463342001e4ccfff5df2d187b3d 192.168.8.124:7679@17679 slave 636a42182b27edde6aee66bc5c8fac11df80336a 0 1594712726590 4 connected
cac8625b5ad4a665d9a5390bf994b3596ef818bf 192.168.8.124:7879@17879 slave 309dd80d9b1cc32fad37f29e4da0db825637df96 0 1594712725580 6 connected
636a42182b27edde6aee66bc5c8fac11df80336a 192.168.8.124:7379@17379 myself,master - 0 1594712726000 1 connected 0-5460
cb7887a912529e231610101a2e1c4eb5ffa571ad 192.168.8.124:7779@17779 slave da9fd04b8fb914ed297f5eb7689aec344f2982cd 0 1594712725000 5 connected
da9fd04b8fb914ed297f5eb7689aec344f2982cd 192.168.8.124:7479@17479 master - 0 1594712726000 2 connected 5461-10922
309dd80d9b1cc32fad37f29e4da0db825637df96 192.168.8.124:7579@17579 master - 0 1594712727601 3 connected 10923-16383
# 执行set操作,发现会重定向到对接节点的槽位
127.0.0.1:7379> set phone 17600000000
-> Redirected to slot [8939] located at 192.168.8.124:7479
OK
192.168.8.124:7479>
注意:本文创建的redis是不带密码的,如果redis设置密码,需要修改redis-trib.rb 文件或者把redis版本升级到5.0.0以上
4、集群扩容
4.1、5.0.0之后版本(本文使用的是5.0.0以下的版本,以上的类似,这里贴了使用命令)
# 扩容
1.
# 添加master节点
# 注意语法,一个新节点IP:端口 空格 一个旧节点IP:端口,注意点是:
# 1.不能多个新节点一次性添加
# 2.新节点后是旧节点
# 3.如果设置--cluster-slave,新节点挂在旧节点下的一个从节点
# 4.如果设置 --cluster-master-id ,arg设置旧节点的id,具体可以使用cluster nodes查看各个节点的id
# add-node new_host:new_port existing_host:existing_port --cluster-slave --cluster-master-id
# 此时 192.168.8.124:7979 为一个新的master节点
redis-cli --cluster add-node 192.168.8.124:7979 192.168.8.124:7379
2.
# 添加到从节点 此时192.168.8.124:8079 为 192.168.8.124:7979 的从节点
redis-cli --cluster add-node 192.168.8.124:8079 192.168.8.124:7979 --cluster-slave
这里是将节点加入了集群中,但是并没有分配slot,所以这个节点并没有真正的开始分担集群工作。
3.
# 这里是将节点加入了集群中,但是并没有分配slot,所以这个节点并没有真正的开始分担集群工作
# 分配slot
redis-cli --cluster reshard 192.168.8.124:7979 --cluster-from 2846540d8284538096f111a8ce7cf01c50199237,e0a9c3e60eeb951a154d003b9b28bbdc0be67d5b,692dec0ccd6bdf68ef5d97f145ecfa6d6bca6132 --cluster-to 46f0b68b3f605b3369d3843a89a2b4a164ed21e8 --cluster-slots 1024
--cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔
--cluster-to:表示需要新分配节点的node ID(貌似每次只能分配一个)
--cluster-slots:分配的slot数量
4.
# 添加slave节点
redis-cli --cluster add-node 127.0.0.1:6386 127.0.0.1:6385 --cluster-slave --cluster-master-id 46f0b68b3f605b3369d3843a89a2b4a164ed21e8
add-node: 后面的分别跟着新加入的slave和slave对应的master
cluster-slave:表示加入的是slave节点
--cluster-master-id:表示slave对应的master的node ID
# 收缩
4、收缩集群
下线节点127.0.0.1:6385(master)/127.0.0.1:6386(slave)
1.
首先删除master对应的slave
redis-cli --cluster del-node 127.0.0.1:6386 530cf27337c1141ed12268f55ba06c15ca8494fc
del-node后面跟着slave节点的 ip:port 和node ID
2.
清空master的slot
redis-cli --cluster reshard 127.0.0.1:6385 --cluster-from 46f0b68b3f605b3369d3843a89a2b4a164ed21e8 --cluster-to 2846540d8284538096f111a8ce7cf01c50199237 --cluster-slots 1024 --cluster-yes
reshard子命令前面已经介绍过了,这里需要注意的一点是,由于我们的集群一共有四个主节点,而每次reshard只能写一个目的节点,因此以上命令需要执行三次(--cluster-to对应不同的目的节点)。
--cluster-yes:不回显需要迁移的slot,直接迁移。
3.
下线(删除)节点
redis-cli --cluster del-node 127.0.0.1:6385 46f0b68b3f605b3369d3843a89a2b4a164ed21e8
至此就是redis cluster 简单的操作过程
4.2、扩容 5.0.0版本之前
4.2.1 扩容
# 进入redis-trib容器
docker exec -it redis-trib bash
# 添加节点 192.168.8.124:7979为新节点,192.168.8.124:7379任一老节点都可以
ruby redis-trib.rb add-node 192.168.8.124:7979 192.168.8.124:7379
-
添加完后进入任一redis实例中,查看集群节点,如下图
- 新节点7979现在已经连接上了集群, 成为集群的一份子, 并且可以对客户端的命令请求进行转向了, 但是和其他主节点相比, 新节点还有两点区别:
- 新节点没有包含任何数据, 因为它没有包含任何哈希槽.
- 尽管新节点没有包含任何哈希槽, 但它仍然是一个主节点, 所以在集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中。
- 接下来, 只要使用 redis-trib 程序, 将集群中的某些哈希桶移动到新节点里面, 新节点就会成为真正的主节点了。
- 分配哈希槽
# 给7979分配哈希槽
ruby redis-trib.rb reshard 192.168.8.124:7979
日志如下
- 接下来输入yes就ok了,分配完成后,查看集群信息(如下图),此时已分配哈希槽
4.2.2 为192.168.8.124:7979添加从节点
# 添加从节点
# --slave 表明此时添加的是从节点 --master-id 后跟主节点id
# 192.168.8.124:8079 192.168.8.124:7979 前面是新添加的从节点,后面为对应的主节点
ruby redis-trib.rb add-node --slave --master-id 8598e877be674cf31ce1bbf3bdb8cce0cb053482 192.168.8.124:8079 192.168.8.124:7979
4.2.3 查看集群状态,此时已经多了从节点信息
5、集群缩容
5.1、使用del-node命令
# 删除从节点
# del-node host:port node_id
ruby redis-trib.rb del-node 192.168.8.124:8079 1ceb81491eace626d601fc0fcfdc569b8e4e896f
- 此时,8079节点已从集群中移除
5.2、删除主节点
# 删除主节点,删除主节点之前,要将slots分配到其他主节点上
ruby redis-trib.rb reshard 192.168.8.124:7979
-
日志如下图
- 7979节点中有4096个slots,直接输入4096,enter
5.3、选择接收的节点id,可以选择其他的主节点id
此时选择的是7379的主节点id,all为所有主节点,done:指定节点
可以把分配的过程理解成打扑克牌,
- all表示大家重新洗牌;
- 输入某个主节点的node id,然后在输入done的话,就好比从某个节点,抽牌
日志如下:
注意:此处与4.2.1分配类似
5.4、查看集群信息
5.5、删除主节点
# 删除主节点
ruby redis-trib.rb del-node 192.168.8.124:7979 8598e877be674cf31ce1bbf3bdb8cce0cb053482
5.6、进入其他的主节点,查看集群节点信息,发现已经没有7979节点
# 注意,如果中间重新分配slots时,出现错误
Please fix your cluster problems before resharding
执行脚本 ruby redis-trib.rb fix 192.168.8.124:7979,也出现错误时
[ERR] Calling MIGRATE: ERR Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY)
- 找到对应的slots的节点
# 先执行flushall
127.0.0.1:6379> flushall
# 再执行bgsave
127.0.0.1:6379> bgsave
- 再ruby redis-trib.rb fix 192.168.8.124:7979,如果还是报错
打开redis-trib.rb
# 全局搜索source.r.client.call,替换为source.r.call,总共有2处
source.r.call