背景
项目的某个模块集成了 SpringBoot Redis 包,客户端使用 Lettuce,Redis 测试环境单机模式。但是现场反馈的 Redis 环境是集群,如果简单的修改 spring.redis
配置为集群的配置信息,程序能否能无缝衔接呢?
本文记录这个问题的验证过程:
- 集群配置和单机配置,直接改配置,Redis 操作是否正常?「可以」。
- 同时配置单机和集群信息,哪个配置会优先呢?「集群优先」。
- 集群模式下,主备份切换过程中,程序能否自动找到新的主节点正常读写呢?「Jedis 客户端可以,Luttcue 需要改造」
- 温故一下 Redis 的三种多节点部署方案及其优缺点。
基础准备
第一,Redis 客户端种类, Jedis 、Lettuce 、Redisson,本文选择的是 Lettuce 。
第二,Redis 版本选择 6.2.13,在目标主机上编译完成后并安装:
- 下载 6.2.13 版本,上传服务器。
- 解压,执行编译命令:
make
。 - 安装,指定安装目录:
make install PREFIX=/usr/local/redis6.2.13
第三,Redis 高可用部署方式有三种:
- 主从模式,出现故障需要人工干预;主节点可以读写,从节点只能读不能写。
- 哨兵模式,是对主从的高可用改进,哨兵监控集群状态,出现故障自动处理。
- 集群模式,Redis 的分布式方案,数据分散在多个节点上,无中心的。连接从节点执行写入操作,会自动重定向到主节点完成写入。
集群环境搭建
首先,要注意,6.2.13 版本的集群部署后,会占据两个端口,一个是 Redis 的通信端口,是配置文件中配置的 port
值,另一个是集群通信端口,port + 1000
,所以集群配置时需要注意端口,配置小一点,否则总会莫名其秒端口被占用。
例如,我最初设计的集群各节点的端口是 16793,26793,36793,结果启动的时候总有几个节点启动时端口被其他 Redis 进程占据了。
其次,由于资源有限,在一台主机上,部署三主三从6个 Redis 实例。选择节点从 7000 到 7005 ,搭建集群。
- 进入安装目录 /usr/local/redis6.2.13,按实例端口创建文件夹 mkdir 7000。
- 到 Redis 源码文件夹下,拷贝一个标准配置文件 redis.conf 到 7000 中。
- 编辑 redis.conf 修改跟集群配置相关的几项信息。
bind 0.0.0.0
daemonize yes
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
pidfile /var/run/redis_7000.pid
logfile /usr/local/redis6.2.13/7000/7000.log
dbfilename 7000.rdb
接着,继续创建其他 5 个节点配置文件:
- 以 7000 目录 为基础,拷贝:
cp -r 7000 7001
,编辑 7001/redis.conf , 命令模式下执行字符串替换操作::%s/7000/7001
替换所有的 7000 。 - 以此拷贝出 7002-7005 个配置文件。
- 启动节点:进入 bin 目录下
redis-server ../7000/redis.conf
依次启动全部节点。
最后一步,使用 redis-cli 客户端创建集群:./redis-cli --cluster create 192.168.xx:7000 192.168.xx:7001 192.168xx:7002 192.168.xx:7003 192.168.xx:7004 192.168.xx:7005 --cluster-replicas 1
一路 yes ,耐心等待集群创建完成,查看集群节点进程:
查看某个 Redis 节点的进程端口,可以看到一个 Redis 进程启动了两个端口。因为每个Redis集群中的节点都需要打开两个TCP连接,一个连接用于正常的给Client提供服务,比如 6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,参考该文 《Redis 集群节点启动的两个端口说明》。
参考网上 5.x 版本的部署方案,只有一个端口,可能 6 的版本跟 5 的有差距吧。
验证集群配置
当前应用直接改配置,是否支持集群?
直接修改应用的 redis 配置信息,添加集群配置:
spring:redis:password: x #密码lettuce: #lettuce连接池配置pool:max-active: 8max-idle: 8min-idle: 0max-wait: 1000shutdown-timeout: 100cluster: #集群配置max-redirects: 3nodes: # 配置 - 间隔一个好像也没报错呢。- 192.168.x:7000- 192.168.x:7001- 192.168.x:7002- 192.168.x:7003- 192.168.x:7004- 192.168.x:7005
启动应用,执行 Redis 操作正确,说明直接用框架的自动注入,是支持集群的。
集群主节点故障验证
登录 7000 节点,使用 cluster nodes
查看集群节点,找到一个 master 节点的端口号,登录该主节点后,shutdown
命令停掉该主节点。
引用 Redis 集群的程序在获取 RedisConnection
时出现了超时异常,而且即使主节点恢复了,程序依旧报错,这就涉及到了 《Lettuce 客户端的另外一个坑》。
因为不确定到底使用 Redis 集群还是单机,所以对 Lettuce 自动刷新集群拓扑图配置类注入使用一个开关参数控制,如果是集群,就可以保证集群变更时,客户端实时感知了。
从执行日志来看,无论我停止那个主节点,应用都会报该节点连接异常,继续重试。
DefaultClusterTopologyRefresh : Unable to connect to [192.168.x:7005]: connection timed out: /192.168.x:7005
猜测应该是这个定时刷新任务会对配置的集群节点逐个轮训发送数据判断是否可达吧。
配置优先级
同时配置 host 和 cluster 会怎么样?
集群模式下,只配置一个 host 单机配置,会报错,因为有些请求会产生 moved
或者重定向等问题。同时配置单机节点和集群,集群优先。
判断依据:停掉一个集群主节点后,后台开始刷新重连接尝试,应用正常运行。
集群模式下的读写操作
./redis-cli -h 192.168.X -p 7000 -c
Redis 自带的客户端,-c
这个参数代表集群模式,集群模式下,如果连接从节点,执行写入操作,会自动重定向到主节点完成写入:
不带 -c
参数,会提示一个 moved 地址,需要手动转到该地址执行写入操作:
启示录
集群模式跟主备模式不同,不同节点上执行 keys 的时候,并不是所有节点都有相同的数据。因为集群的本质就是数据分散存储,并不是每个节点上都存储了全部的数据的。
验证完本文这个问题后,把《Redis 开发与运维》这本书拿出来翻了翻,全忘光了。脑子不够用了,还是手动敲一遍,作为笔记留存吧!