Redis 集群搭建(四):Docker 部署 Redis + Cluster 分布式水平扩展高可用集群
前言
目录: 我这里统一放在 /data/redis/cluster
下面,Redis
每个位置为 /data/redis/cluster/{port}
每个文件夹都包含以下目录:
- conf: 配置文件文件夹
- data: 主要文件挂载,包含持久化文件之类的
- logs: 日志文件目录,这会把日志文件夹也挂出来,好看一些打印
官方译文
cluster 的优点
- 去中心化分片: 原理采用hash槽的概念,预先分配16384个卡槽,并且将该卡槽分配给提供具体服务的Redis片区节点用来存放每个Redis主机对应卡槽范围的数据。
PS:也就是每个 Redis 仅对应一个分片区域即卡槽,减少缓存雪崩导致数据丢失带来的意外风险。
参考: 分布式缓存Redis_7 Redis Cluster去中心化分片集群 - 水平扩展: 可线性扩展到 1000 多个节点,节点可动态添加或删除。
- 配置简单: 与
Sentinel
相比配置简单很多,不需要自己指定主从节点之类的,cluster
会自动完成。 - 故障转移: 部分节点不可用时,集群仍可用。通过增加 Slave 做 standby 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升。
集群不可用情况
- 集群主库半数宕机(无论是否从库存活)
PS:一般服务器崩溃,上面的库都宕机 - 集群某一节点的主从全数宕机。
由于只要有一台的主从全部宕机集群就不可用,因此正常情况,主库下面一定要跟从库,主库宕机后, cluster 会自动选举出从库顶替主库,不需要配置全自动,之后恢复故障的 Redis 就好了
部署
新建模板
redis-cluster.tmpl: 用于通过这个模板文件可以直接命令行生成对应的 redis.conf
配置文件,顺手生成挂载目录啥的
PS:可以看到端口号都是变量,之后只需替换端口号生成对应配置文件即可
上半部分是 redis 的配置,下半部分为 cluster 的配置
cat << EOF > /data/redis/cluster/redis-cluster.tmpl
# redis 相关配置
# redis 端口号
port ${PORT}
# RDB 持久化,快照保存频率
# 900秒内,如果超过1个key被修改,则发起快照保存
# 300秒内,如果超过10个key被修改,则发起快照保存
# 60秒内,如果1万个key被修改,则发起快照保存
save 900 1
save 300 10
save 60 10000
# 在进行数据镜像备份时,是否启用rdb文件压缩手段,默认为yes。
rdbcompression yes
# 解决 Redis 被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用。
stop-writes-on-bgsave-error no
# 开启 AOF 持久化
appendonly yes
# 设置密码
requirepass "123456"
# 开启保护模式
protected-mode no
# redis 日志文件地址
logfile "/redis/logs/redis.log"
# 设置主库的密码,挂了切换,也需要密码
masterauth "123456"
# 不限制访问
bind 0.0.0.0
# cluster 相关配置
# 启动集群模式
cluster-enabled yes
# 配置文件指定名称,这个配置文件主要 redis 自己维护,我们不需要管
cluster-config-file nodes.conf
# 连接超时时间
cluster-node-timeout 5000
# 集群 IP,即服务器 IP
cluster-announce-ip 118.25.215.105
# 集群端口
cluster-announce-port ${PORT}
# 集群总线端口,用于集群之间进行通信
cluster-announce-bus-port 1${PORT}
EOF
生成虚拟网卡
创建虚拟网卡,主要是用于redis-cluster能于外界进行网络通信,一般常用桥接模式。
docker network create redis-net
生成配置文件
PS:顺手把文件加也生成了
seq: 意思是 6382 - 6384 之间的正整数
envsubst: 替换变量,然后生成新的文件
PS:done 也就是循环完成前面的分号
for port in $(seq 6382 6384); \
do \
mkdir -p /data/redis/cluster/${port}/conf \
&& PORT=${port} envsubst < /data/redis/cluster/redis-cluster.tmpl > /data/redis/cluster/${port}/conf/redis.conf \
&& mkdir -p /data/redis/cluster/${port}/{data,logs}; \
done
PS:我这里其他的像 log,是我已经启动挂在出来的,没有 tree 命令,可以直接 yum 安装
循环生成 Redis 容器
解释下含义,从 port 那行开始
- 端口号挂载,
Redis
端口号以及集群总线端口
- 使用
redis-net
网络 - 监听队列的长度加大到 1024,防止高负载的环境过小
- 挂载 redis 配置文件
- 挂载主要文件
- 挂载日志文件
- 通过
redis-server
启用自己的配置文件
PS:done 也就是循环完成前面的分号
for port in $(seq 6382 6384); \
do \
docker run -d --name redis-${port} \
-p ${port}:${port} -p 1${port}:1${port} \
--net=redis-net \
--sysctl net.core.somaxconn=1024 \
-v /data/redis/cluster/${port}/conf:/redis/conf \
-v /data/redis/cluster/${port}/data:/data \
-v /data/redis/cluster/${port}/logs:/redis/logs redis \
redis-server /redis/conf/redis.conf; \
done
启动后,redis 节点已经启用完毕,还需要将他们串成一个集群
串联生成集群
随便在一个容器中执行即可
- -a:
Redis
密码,如果你有设置的话 - -replicas: 每个主节点对应几个子节点,我这里资源有限没配置,即没有子节点,例:
-replicas 1
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster create \
118.25.215.105:6382 118.25.215.105:6383 118.25.215.105:6384'
成功
Redis Cluster 命令
参考命令行
docker exec -it redis-6382 /bin/bash -c 'redis-cli -a 123456 --cluster help'
新增节点
增加配置
操作与之前的一样,先生成配置文件,然后通过命令直接生成容器,注意赋予文件夹权限
端口号: 6385,6386,6387
添加节点
PS:下面都以 6385 添加为例
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster add-node 118.25.215.105:6385 118.25.215.105:6382'
PS:注意,这里添加的 6385
端口的为新的节点,6382
为已存在节点,新节点必须通过一个已经存在的节点加入集群
通过 check
命令先看下现在的情况
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster check 118.25.215.105:6382'
可以看到,节点已经添加为 master
但是由于槽已经分配过了,所以新节点没分配到槽(0 slots),我们需要对他们再分配下
重新切分集群
rebalance: 通过 rebalance
对槽进行重分配,也可以使用 reshard
属性选择具体需要分配多少
–cluster-use-empty-masters:rebalance
是否考虑没有节点的 master
,默认没有分配 slot
节点的 master
是不参与 rebalance
的,设置 --cluster-use-empty-masters
可以让没有分配 slot
的节点参与rebalance
。
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster rebalance --cluster-use-empty-masters 118.25.215.105:6382'
可以看到槽重分配了
原来的每个 master
的槽都被分了点给了 6385
端口
删除节点
移动槽
依然以 6385
为例,由于 6385
上存在槽,所以是删不掉的,需要先把槽移动到其他的节点,这里把
6385
上的槽全部移动到 6382
上
–cluster-from: 槽移动的来源,值为节点的 ID
–cluster-to: 槽移到哪去,值为节点的 ID
–cluster-slots: 移动的槽的数量
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster reshard 118.25.215.105:6382 \
--cluster-from 54a85ce32e1e93cd748c87818a8b9b03abeab216 \
--cluster-to 7c4ec39709a65d133610c375aee98f458ede8778 \
--cluster-slots 4096'
一堆 Moving 后 6385
已经没槽了,可以删了
删除节点
PS:54a85ce32e1e93cd748c87818a8b9b03abeab216 是具体删除节点的 ID,前面的都只是用来获取集群数据的
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -a 123456 --cluster del-node 118.25.215.105:6382 \
54a85ce32e1e93cd748c87818a8b9b03abeab216'
节点变更
指定某节点为另一个节点的从节点
先利用 add-node 指令添加节点 redis-6386
为 6385
节点的从节点
接下来再利用命令指定节点为某个节点的从节点
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -p 6386 cluster replicate \
54a85ce32e1e93cd748c87818a8b9b03abeab216'
格式
docker exec -it redis-6382 /bin/bash -c \
'redis-cli -p <从节点的端口号> cluster replicate <主节点ID>'
SpringBoot 连接 Cluster
SpringBoot 整合 Redis 及 Redis 工具类
修改 Redis 配置,以及线程池改为 lettuce
,cluster
默认使用的是 lettuce
线程池
#Redis配置
redis:
password: 123456
cluster:
nodes: 118.25.215.105:6382,118.25.215.105:6383,118.25.215.105:6384
max-redirects: 3
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中最小空闲连接
min-idle: 0
# 连接超时时间(毫秒)
timeout: 1000ms