Redis 哨兵集群搭建并使用 RedisTemplate 实现读写分离
上篇博客介绍的 Redis 主从集群搭建,有一个缺点就是 master 和 slave 的角色是固定的,不会发生变化。一旦 master 节点宕机,那么集群就只能提供读服务,无法提供写服务。本篇博客介绍 Redis 哨兵集群的搭建,可以监控 Redis 集群的 master 和 slave 节点,最重要的是一旦 master 宕机,哨兵集群内部会投票选举出一个 slave 节点作为 master 节点,之前的 master 节点如果恢复后,就会变成新 master 的 slave 节点。
本篇博客的代码 Demo 也在上篇博客的基础上,不需要修改任何代码,只需要修改一下 application.yml 文件,即可实现 RedisTemplate 连接哨兵集群实现读写分离的效果,在博客的最后会提供源代码的下载。
一、哨兵集群的搭建
有了上篇博客搭建 Redis 主从集群的经验,那么搭建 Redis 哨兵集群就非常简单,本篇博客仍然使用虚拟机进行模拟搭建,我的虚拟机操作系统是 CentOS7(ip 地址是 192.168.136.128),已经安装好了 docker 和 docker-compose
首先我们先创建好目录 /app/redis-cluster-sentinel ,在其下面创建好相关的 redis 和 sentinel 目录:
上图是我已经搭建好的 Redis 哨兵集群目录结构,直接拿来用了。除了 Redis 是主从集群之外,哨兵 Sentinel 本身也是一个 3 节点的集群,因此创建了 3 个 sentinel 的文件夹,里面只存放 sentinel.conf 配置文件。
Redis 集群 3 个节点的配置文件 redis.conf 跟上篇博客的主从集群配置文件一模一样。唯一的不同在于 master 节点的 redis.conf 配置文件,需要多配置一行访问主节点的密码配置,即 masterauth [主节点的访问密码] ,因为 master 节点在实际情况下,有可能会宕机,sentinel 集群会从其它 slave 节点选出一个作为 master 节点,此时之前的 master 节点恢复后就会变成 slave 节点,去连接新的 master 节点同步数据时,也是需要访问 master 节点密码的。
具体 redis1(初始化为 mater 节点)、redis2 和 redis3(这两个节点初始化为 slave 节点)的配置文件如下:
# 这个是 redis1 的配置文件,初始化为 master 节点
protected-mode no
bind 0.0.0.0
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
# 关闭 aof 日志备份
appendonly no
# 自定义密码
requirepass root
# 启动端口
port 6379
# 访问 master 节点时需要提供的密码
masterauth root
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128
# 这个是 redis2 的配置文件,初始化为 slave 节点
protected-mode no
bind 0.0.0.0
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
# 关闭 aof 日志备份
appendonly no
# 启动端口
port 6479
# 将当前 redis 作为 redis1 的 slave
# 由于 docker 使用 host 模式,使用的是宿主机的 ip
slaveof 192.168.136.128 6379
# 自定义密码
requirepass root
# 访问 master 节点时需要提供的密码
masterauth root
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128
# 这个是 redis3 的配置文件,初始化为 slave 节点
protected-mode no
bind 0.0.0.0
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
# 关闭 aof 日志备份
appendonly no
# 启动端口
port 6579
# 将当前 redis 作为 redis1 的 slave
# 由于 docker 使用 host 模式,使用的是宿主机的 ip
slaveof 192.168.136.128 6379
# 自定义密码
requirepass root
# 访问 master 节点时需要提供的密码
masterauth root
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128
然后我们列出 3 个哨兵的配置文件 sentinel.conf 的具体细节:
# 这是 sentinel1 的配置文件
port 26379
protected-mode no
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.136.128
# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.136.128 6379 2
# sentinel 会向集群中的节点定期发送心跳检测命令,
# 如果在配置时间(毫秒)内没有响应回复,则被认为是主观下线
sentinel down-after-milliseconds jobs 5000
# 主备切换时,最多有多少个 slave 同时对新的 master 进行同步
sentinel parallel-syncs jobs 2
# 故障转移的超时时间
sentinel failover-timeout jobs 60000
# 如果在 Redis 设置了密码,这里就需要提供访问密码
sentinel auth-pass jobs root
# 这里设置访问 sentinel 的密码
requirepass root
# 数据存储目录
dir /data
# 这是 sentinel2 的配置文件
port 26479
protected-mode no
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.136.128
# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.136.128 6379 2
# sentinel 会向集群中的节点定期发送心跳检测命令,
# 如果在配置时间(毫秒)内没有响应回复,则被认为是主观下线
sentinel down-after-milliseconds jobs 5000
# 主备切换时,最多有多少个 slave 同时对新的 master 进行同步
sentinel parallel-syncs jobs 2
# 故障转移的超时时间
sentinel failover-timeout jobs 60000
# 如果在 Redis 设置了密码,这里就需要提供访问密码
sentinel auth-pass jobs root
# 这里设置访问 sentinel 的密码
requirepass root
# 数据存储目录
dir /data
# 这是 sentinel3 的配置文件
port 26579
protected-mode no
# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.136.128
# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.136.128 6379 2
# sentinel 会向集群中的节点定期发送心跳检测命令,
# 如果在配置时间(毫秒)内没有响应回复,则被认为是主观下线
sentinel down-after-milliseconds jobs 5000
# 主备切换时,最多有多少个 slave 同时对新的 master 进行同步
sentinel parallel-syncs jobs 2
# 故障转移的超时时间
sentinel failover-timeout jobs 60000
# 如果在 Redis 设置了密码,这里就需要提供访问密码
sentinel auth-pass jobs root
# 这里设置访问 sentinel 的密码
requirepass root
# 数据存储目录
dir /data
由于我们要采用 docker 的 host 模式进行部署,因此这里无论是 redis 集群,还是 sentinel 集群,都使用的是虚拟机的 ip 地址 192.168.136.128,因此必须配置不同的端口,具体细节如下:
- redis 集群的 3 个节点的端口为 6379、6479、6579
- sentinel 集群的 3 个节点的端口为 26379、26479、26579
最后在 /app/redis-cluster-sentinel 目录下创建 docker-compose.yml 文件,具体内容如下:
version: "3.5"
services:
redis1:
image: redis
container_name: redis1
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/redis1/data:/data
- /app/redis-cluster-sentinel/redis1/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
redis2:
image: redis
container_name: redis2
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/redis2/data:/data
- /app/redis-cluster-sentinel/redis2/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis1
redis3:
image: redis
container_name: redis3
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/redis3/data:/data
- /app/redis-cluster-sentinel/redis3/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis1
sentinel1:
image: redis
container_name: sentinel1
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/sentinel1/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis1
sentinel2:
image: redis
container_name: sentinel2
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/sentinel2/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis1
sentinel3:
image: redis
container_name: sentinel3
restart: always
privileged: true
network_mode: "host"
volumes:
- /app/redis-cluster-sentinel/sentinel3/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis1
然后在 docker-compose.yml 所在目录运行 docker-compose up -d
命令启动服务即可。
然后使用 docker-compose ps
命令查看服务启动状况:
由于在 docker-compose.yml 文件中,各个服务采用的是 docker 的 host 模式部署,因为看不到启动的端口
可以使用 netstat -tulnp | grep redis
命令查看启动的服务端口
由于使用 RDM 无法运行 sentinel 命令查看哨兵集群的状态,因此我们需要使用 redis 自带的 redis-cli 客户端工具连接 sentinel 查看集群的状态,可以到 GitHub 下载微软提供的 windows 版本的 redis 文件,使用其内部提供的 redis-cli.exe 工具
微软提供的 windows 版本的 redis 下载地址为:https://github.com/MicrosoftArchive/redis/releases
下载好 zip 包,解压缩就可以看到 redis-cli.exe 工具,打开 cmd 命令行,进入到 redis 的目录,运行 redis-cli.exe -h 192.168.136.128 -p 26379
连接其中任意一个 sentinel 节点,然后输入 auth root
(我们设置的访问 sentinel 的连接密码是 root)
运行 sentinel master jobs
可以查看 reids 的 master 节点信息
运行 sentinel slaves jobs
可以查看 reids 的 slave 节点信息
运行 sentinel sentinels jobs
可以如果能够查看到除了本 sentinel 节点外其它 sentinel 节点信息,说明 sentinel 集群搭建成功
从上面命令的运行结果可以看出,sentinel 任意节点,运行以下命令可以获取到所监控的 redis 节点的主从信息:
# 本篇博客的搭建的 sentinel 集群,配置的名称是 jobs
sentinel master [sentinel集群名称]
sentinel slaves [sentinel集群名称]
# 查看除自己之外,sentinel 集群中的其它 sentinel 节点信息
sentinel sentinels [sentinel集群名称]
二、测试 master 节点宕机
从上面的 sentinel 命令运行结果可以看出,当前 redis 节点的主从信息如下:
- master 节点为 redis1(192.168.136.128:6379)
- slaves 节点为 redis2 (192.168.136.128:6479)和 redis3(192.168.136.128:6579)
此时我们运行 Linux 命令停掉 redis1 节点:docker-compose stop redis1
过一小会儿,再启动 redis1 节点:docker-compose start redis1
此时我们再运行 sentinel master jobs
和 sentinel slaves jobs
查看 redis 集群主从信息:
可以发现,现在 master 节点和 slave 节点信息发生的变化:
- master 节点变成了 redis2(192.168.136.128:6479)
- slave 节点变成了 redis1(192.168.136.128:6379)和 redis3(192.168.136.128:6579)
可以看出:redis1 这个 master 节点宕机后,sentinel 集群从 slaves 中选举出了 redis2 作为新的 master 节点,之前的 redis1 即使恢复后,也会作为 redis2 的 slave 节点。这说明 Redis 哨兵集群已经搭建成功,实现了 master 和 slave 的角色切换功能。
我们可以重启集群,恢复以前的 master 和 slave 的状态:docker-compose restart
三、RedisTemplate 操作哨兵集群实现读写分离
本篇博客仍然使用上篇博客的 Demo 代码,一行代码都不需要更改,只需要更改配置文件即可。
这里仅仅列出 application.yml 配置文件的具体内容:
spring:
redis:
# 这里配置的是连接具体的 redis 节点的密码
password: root
sentinel:
# 在 sentinel 中配置的集群名称
master: jobs
# 这里配置的是连接 sentinel 节点的密码
password: root
# 这里只配置 sentinel 集群的节点地址和端口
# 不需要配置具体的 redis 节点
nodes:
- 192.168.136.128:26379
- 192.168.136.128:26479
- 192.168.136.128:26579
jedis:
pool:
# 最大连接数
max-active: 10
# 最大空闲连接数
max-idle: 5
# 最小空闲
min-idle: 1
# 连接超时时间(毫秒)
max-wait: 3000
需要注意的是:
- spring.redis.password 配置的是连接 redis 实例的密码
- spring.redis.sentinel.password 配置的是连接 sentinel 的密码
- spring.reidis.sentinel.nodes 只需要配置 sentinel 集群的节点即可,不需要配置 redis 集群中的节点,因为 RedisTemplate 能够从 sentinel 中获取到 redis 的主从节点的信息。当 redis 主节点变化时,sentinel 能够进行 redis 的 master 和 slave 自动切换,并通知 RedisTemplate 有关 Redis 的 master 和 slave 变化后的信息,从而实现程序自动识别并继续实现读写分离。
跟上篇博客的 Demo 运行情况相似,从控制台日志中,无法看出 RedisTemplate 是从哪个节点读取的数据
验证 RedisTemplate 操作哨兵集群实现读写分离的方法跟上篇博客的方案一样,这里就不再赘述。
本篇博客的源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springboot_redis_cluster2.zip