搭建Redis哨兵集群并使用RedisTemplate实现读写分离

一、理论相关

  • 通过上篇博客:搭建Redis“主-从-从”模式集群并使用 RedisTemplate 实现读写分离,我们已经搭建好了Redis“主-从-从”模式集群并且实现读写分离,这里会出现几个问题:如果主库宕机了,我们就需要运行一个新主库,比如说把一个从库切换为主库,把它当成主库。这就会涉及到三个问题:

    1. 主库真的挂了吗?
    2. 该选择哪个从库作为主库?
    3. 怎么把新主库的相关信息通知给从库和客户端呢?
  • 由此,我们便引出哨兵机制

1、哨兵机制:主库挂了,如何不间断服务?

1.1、哨兵机制的基本流程

一个运行在特殊模式下的Redis进程,主从库实例运行的同时,它也在运行。主要负责三个任务:

  1. 监控 - 需要判断主库是否处于下线状态

    1. 哨兵进程在运行时,周期性地给所有的主从库发送PING命令,检测它们是否仍在线运行
    2. 从库没有在规定时间内响应哨兵的PING命令(对PING命令响应超时),标记为“下线状态”
    3. 主库对PING命令响应超时,判定主库下线,开始自动切换主库的流程
  2. 选主(选择主库) - 决定哪个从库实例作为主库

    1. 主库挂了以后,从很多个从库里,按照一定的规则选择一个从库实例,把它作为新的主库
  3. 通知

    1. 把新主库的连接信息发给其它从库,执行replicaof命令,和新主库建立连接,并进行数据复制
    2. 把新主库的连接信息通知给客户端,让它们把请求操作发到新主库

1.2、主观下线和客观下线

主库:特别注意哨兵误判的情况 - 主库实际没有下线,哨兵误以为下线了

  • 一般发生在集群网络压力较大、网络拥塞,或主库本身压力较大的情况
  • 避免后续没有价值的开销

解决方法:

  • 多实例组成的集群模式进行部署 - 哨兵集群
  • 引入多个哨兵实例一起判断,降低误判率
  • 只有大多数哨兵实例都判断主库已经“主观下线”,主库才会被标记为“客观下线”

image

  • 当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为“主观下线”,才能最终判定主库为“客观下线”
  • 有多少个实例做出“主观下线”的判断才可以 - 可以由 Redis 管理员自行设定

1.3、如何选定新主库?

  • 筛选 + 打分

    1. 在多个从库中,先按照一定的筛选条件,把不符合条件的从库去掉
    2. 再按照一定的规则,给剩下的从库逐个打分,将得分最高的从库选为新主库

image-20241009165754869

  • 筛选条件

    1. 在线状态
    2. 网络连接状态
      • 配置项down-after-milliseconds * 10
      • down-after-milliseconds:认定主从库断连的最大连接超时时间
      • 如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,就可以认为主从节点断连了
      • 发生断连的次数超过10次,这个从库的网络状况不好,不适合作为新主库
  • 打分(在某一轮中,从库得分最高,它就是主库,选主过程结束;否则进行下一轮打分)

    1. 从库优先级(优先级最高的从库得分高)
    • 配置项slave-priority,给不同从库设置不同优先级
    • 比如:两个从库中内存大的实例设置高优先级
    1. 从库复制进度(和旧主库同步程度最接近的从库得分高)
    • 如果选择和旧主库同步最接近的那个从库作为主库,这个新主库上就会有最新的数据
    • slave_repl_offset最接近master_repl_offset
    1. 从库ID号(ID号小的从库得分高)
    • 默认规定

1.4、小结

image

  • 组成哨兵机制可以解决主库之间切换服务的问题,但同样的,引入哨兵机制就相当于再引入实例,那么我们又会面临一些问题:

    1. 哨兵集群中有实例挂了,怎么办,会影响主库状态判断和选主吗?
    2. 哨兵集群多数实例达成共识,判断出主库“客观下线”后,由哪个实例来执行主从切换呢?
  • 那么接下来,我们就引出哨兵集群的概念:

2、哨兵集群:哨兵挂了,主从库还能切换吗?

  • 一旦多个实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作,包括判定主库是不是处于下线状态,选择新主库,以及通知从库和客户端。

2.1、基于pub/sub机制的哨兵集群组成

  • 同时,它也可以从主库上订阅消息,获得其他哨兵发布的连接信息
  • 除了哨兵实例,我们自己编写的应用程序也可以通过 Redis 进行消息的发布和订阅

频道:消息的类别

image

  • 哨兵除了彼此间建立连接形成集群,还需要和从库建立连接
  • 在哨兵的监控任务中,需要对主从库都进行心跳判断,而且在主从库切换完成后,需要通知从库,让它们和新主库同步

image

  • 主从库切换后,客户端也需要知道新主库的连接信息,才能向新主库发送请求操作
  • 哨兵还需要把新主库的信息告诉客户端
  • 客户端需要获取到哨兵集群在监控、选主、切换这个过程中发生的各种事件

2.2、基于pub/sub机制的客户端事件通知

  • 从本质上说,哨兵就是一个运行在特定模式下的 Redis 实例,只不过它并不服务请求操作,只是完成监控、选主和通知的任务。
  • 每个哨兵实例也提供pub/sub机制

image

操作步骤:

  1. 客户端读取哨兵的配置文件
  2. 获得哨兵的地址和端口,和哨兵建立网络连接
  3. 在客户端执行订阅命令,获取不同的事件消息
SUBSCRIBE +odown
PSUBSRCIBE *
switch-master <master name> <oldip> <oldport> <newip> <newport>
  • 表示主库已经切换,新主库的IP地址和端口信息已经有了
  • 客户端不仅可以在主从切换后得到新主库的连接信息,还可以监控到主从库切换过程中发生的各个重要事件
  • 客户端就可以知道主从切换进行到哪一步,有助于了解切换进度

2.3、由哪个哨兵执行主从切换?

  • “投票仲裁”过程

image

在投票过程中,任何一个想成为 Leader 的哨兵,要满足两个条件:

  1. 拿到半数以上的赞成票
  2. 拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值

3个哨兵、quorum为2的选举过程:

时间 哨兵1(S1) 哨兵2(S2) 哨兵3(S3)
T1 判断主库为“客观下线”,给自己投1票Y,向S2、S3发投票请求,表示要成为Leader
T2 判断主库为“客观下线”,给自己投1票Y,向S1、S3发投票请求,表示要成为Leader
T3 收到S3的请求,回复N(已经给自己投了一票Y,不能再给其它哨兵投Y) 收到S3的请求,回复Y
T4 收到S1的请求,回复N(网络传输可能拥塞了,导致投票请求传输慢了)
T5 1票Y,1票N 2票Y,成为Leader
  • 如果S3没有拿到2票Y,这轮投票就不会产生Leader,哨兵集群会等待一段时间(也就是哨兵故障转移超时时间的 2 倍),再重新选举。
  • 如果哨兵集群只有 2 个实例,此时,一个哨兵要想成为 Leader,必须获得 2 票,而不是 1 票。所以,如果有个哨兵挂掉了,那么,此时的集群是无法进行主从库切换的。因此,通常我们至少会配置 3 个哨兵实例。

2.4、小结

image

哨兵集群的关键机制

  1. 基于 pub/sub 机制的哨兵集群组成过程;
  2. 基于 INFO 命令的从库列表,这可以帮助哨兵和从库建立连接;
  3. 基于哨兵自身的 pub/sub 功能,这实现了客户端和哨兵之间的事件通知。
  • 要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds
  • 可能会因为这个值在不同的哨兵实例上配置不一致,导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定。

二、实践

运行环境:虚拟机操作系统:centOS7,IP地址:192.168.88.130

centOS 环境下已经安装好了 docker 和 docker-compose

Windows 环境下已经安装好了 redis-cli.exe 工具(用来查看哨兵集群状态)

采用Redis:7.4.0


在上一篇博文中,我们搭建了Redis主从库集群,结构如下:

[root@centos redis-cluster]# find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
.
|____docker-compose.yml
|____redis0
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis1
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis2
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis3
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis4
| |____data
| | |____dump.rdb
| |____redis.conf
  • 其中,redis0为主库,redis1redis2分别为从库I、从库II;redis3redis4分别为从库II的从库1和从库2

  • 接下来,我们在该结构的基础上,搭建sentinel哨兵集群

  1. 首先,我们先看看上一次搭建集群的redis.conf

    • redis0/redis.conf
    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
    
    # 换成自己的虚拟机的IP
    replica-announce-ip 192.168.88.130
    
    • redis1/redis.conf
    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 作为 redis0 的 slave
    # 由于 docker 使用 host 模式,使用的是宿主机的 ip
    replicaof 192.168.88.130 6379
    
    # 自定义密码
    requirepass root
    
    # 访问 master 节点时需要提供的密码
    masterauth root
    
    masteruser redis0
    
    replica-announce-ip 192.168.88.130
    
    • redis2/redis.conf
    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 作为 redis0 的 slave
    # 由于 docker 使用 host 模式,使用的是宿主机的 ip
    replicaof 192.168.88.130 6379
    
    # 自定义密码
    requirepass root
    
    # 访问 master 节点时需要提供的密码
    masterauth root
    
    replica-announce-ip 192.168.88.130
    
    • redis3/redis.conf
    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 6679
    
    # 将当前 redis 作为 redis2 的 slave
    # 由于 docker 使用 host 模式,使用的是宿主机的 ip
    replicaof 192.168.88.130 6579
    
    # 自定义密码
    requirepass root
    
    # 访问 master 节点时需要提供的密码
    masterauth root
    
    replica-announce-ip 192.168.88.130
    
    • redis4/redis.conf
    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 6779
    
    # 将当前 redis 作为 redis2 的 slave
    # 由于 docker 使用 host 模式,使用的是宿主机的 ip
    replicaof 192.168.88.130 6579
    
    # 自定义密码
    requirepass root
    
    # 访问 master 节点时需要提供的密码
    masterauth root
    
    replica-announce-ip 192.168.88.130
    

1、搭建sentinel

  1. 新建目录
[root@centos redis-cluster]# mkdir sentinel1
[root@centos redis-cluster]# mkdir sentinel2
[root@centos redis-cluster]# mkdir sentinel3
[root@centos redis-cluster]# mkdir sentinel1/data
[root@centos redis-cluster]# mkdir sentinel2/data
[root@centos redis-cluster]# mkdir sentinel3/data
  1. 编辑sentinel.conf
[root@centos redis-cluster]# vi sentinel1/sentinel.conf
port 26379
protected-mode no

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.88.130

# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.88.130 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

[root@centos redis-cluster]# vi sentinel2/sentinel.conf
port 26479
protected-mode no

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.88.130

# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.88.130 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

[root@centos redis-cluster]# vi sentinel3/sentinel.conf
port 26579
protected-mode no

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
sentinel announce-ip 192.168.88.130

# 配置监控的集群主节点的 ip 和 端口
# 如果有 2 个 sentinel 节点认为主节点主观下线,
# 则主节点就被认为是客观下线
# redis 的集群名称可以随意配置,这里配置为 jobs
sentinel monitor jobs 192.168.88.130 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
  1. 然后,我们在docker-compose.yml添加sentinel的配置项
[root@centos redis-cluster]# vi docker-compose.yml
services:
  redis0:
    image: redis
    container_name: redis0
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/redis0/data:/data
      - /root/docker/redis-cluster/redis0/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf

  redis1:
    image: redis
    container_name: redis1
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/redis1/data:/data
      - /root/docker/redis-cluster/redis1/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis0

  redis2:
    image: redis
    container_name: redis2
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/redis2/data:/data
      - /root/docker/redis-cluster/redis2/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis0

  redis3:
    image: redis
    container_name: redis3
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/redis3/data:/data
      - /root/docker/redis-cluster/redis3/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis2

  redis4:
    image: redis
    container_name: redis4
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/redis4/data:/data
      - /root/docker/redis-cluster/redis4/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis2

  sentinel1:
    image: redis
    container_name: sentinel1
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/sentinel1/sentinel.conf:/etc/sentinel.conf
    command:
      redis-sentinel /etc/sentinel.conf
    depends_on:
      - redis0
 
  sentinel2:
    image: redis
    container_name: sentinel2
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/sentinel2/sentinel.conf:/etc/sentinel.conf
    command:
      redis-sentinel /etc/sentinel.conf
    depends_on:
      - redis0
 
  sentinel3:
    image: redis
    container_name: sentinel3
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /root/docker/redis-cluster/sentinel3/sentinel.conf:/etc/sentinel.conf
    command:
      redis-sentinel /etc/sentinel.conf
    depends_on:
      - redis0
  1. 最后,我们在docker-compose.yml 所在目录运行 docker-compose up -d 命令启动服务
[root@centos redis-cluster]# docker-compose up -d
[+] Running 8/8
 ✔ Container redis0     Running                                                                                                                                                                              0.0s 
 ✔ Container redis2     Running                                                                                                                                                                              0.0s 
 ✔ Container redis4     Running                                                                                                                                                                              0.0s 
 ✔ Container sentinel1  Started                                                                                                                                                                              0.4s 
 ✔ Container sentinel2  Started                                                                                                                                                                              0.4s 
 ✔ Container sentinel3  Started                                                                                                                                                                              0.2s 
 ✔ Container redis1     Running                                                                                                                                                                              0.0s 
 ✔ Container redis3     Running
  • 还可以通过docker-compose ps查看集群运行状态
[root@centos redis-cluster]# docker-compose ps
NAME        IMAGE     COMMAND                   SERVICE     CREATED          STATUS          PORTS
redis0      redis     "docker-entrypoint.s…"   redis0      4 days ago       Up 41 minutes   
redis1      redis     "docker-entrypoint.s…"   redis1      4 days ago       Up 41 minutes   
redis2      redis     "docker-entrypoint.s…"   redis2      4 days ago       Up 41 minutes   
redis3      redis     "docker-entrypoint.s…"   redis3      4 days ago       Up 41 minutes   
redis4      redis     "docker-entrypoint.s…"   redis4      4 days ago       Up 41 minutes   
sentinel1   redis     "docker-entrypoint.s…"   sentinel1   17 minutes ago   Up 35 seconds   
sentinel2   redis     "docker-entrypoint.s…"   sentinel2   17 minutes ago   Up 17 minutes   
sentinel3   redis     "docker-entrypoint.s…"   sentinel3   17 minutes ago   Up 17 minutes 

2、在Windows环境下查看虚拟机中搭建的哨兵状态

  1. 进入到 Redis 目录,在该目录下打开 cmd 命令行,运行 redis-cli.exe -h 192.168.88.130 -p 26379 -a root

image-20241009192901554

  1. 查看master节点的信息
sentinel master [sentinel集群名称]

image-20241009193355145

  1. 查看除自己之外,sentinel 集群中的其它 sentinel 节点信息
sentinel sentinels [sentinel集群名称]

image-20241009195419792

image-20241009195457636

  1. 查看slave节点的信息
sentinel slaves [sentinel集群名称]

image-20241009193715097

image-20241009193811267

  • 注:哨兵不直接支持级联从节点的监控(即哨兵一般不会监控从节点的从节点 - 我们所搭建的redis3和redis4),最佳实践通常是避免级联结构,使用简单的“主从”模式,减少管理和故障切换的复杂性。
  • 因此,我们搭建的redis集群如下:

image-20241009195201644

3、模拟master节点宕机

  1. 我们将主库redis0停止再开机:
[root@centos redis-cluster]# docker-compose stop redis0
[+] Stopping 1/1
 ✔ Container redis0  Stopped                                                                                                                                                                                 0.9s 
[root@centos redis-cluster]# docker-compose start redis0
[+] Running 1/1
 ✔ Container redis0  Started
  1. 我们再在sentinel中查看主从信息,便会发现主库更新,原本的redis0主库更换为从库。

三、RedisTemplate

  • 配置文件参考:
spring:
    data:
        redis:
            # 这里只需配置主节点的信息即可
            # RedisTemplate可以从主节点信息中获取从节点信息
            host: 192.168.88.130
            port: 6379
            password: root
            jedis:
                pool:
                    # 最大连接数
                    max-active: 10
                    # 最大空闲连接数
                    max-idle: 5
                    # 最小空闲
                    min-idle: 1
                    # 连接超时时间(毫秒)
                    max-wait: 8000
            sentinel:
                password: root
                master: jobs
                nodes: 
                    - 192.168.88.130:26379
                    - 192.168.88.130:26479
                    - 192.168.88.130:26579

个人问题记录:

  1. 在搭建sentinel时:

    [root@centos redis-cluster]# docker-compose ps
    NAME        IMAGE     COMMAND                   SERVICE     CREATED         STATUS                          PORTS
    redis0      redis     "docker-entrypoint.s…"   redis0      4 days ago      Up 26 minutes                   
    redis1      redis     "docker-entrypoint.s…"   redis1      4 days ago      Up 26 minutes                   
    redis2      redis     "docker-entrypoint.s…"   redis2      4 days ago      Up 26 minutes                   
    redis3      redis     "docker-entrypoint.s…"   redis3      4 days ago      Up 26 minutes                   
    redis4      redis     "docker-entrypoint.s…"   redis4      4 days ago      Up 26 minutes                   
    sentinel1   redis     "docker-entrypoint.s…"   sentinel1   2 minutes ago   Restarting (1) 20 seconds ago   
    sentinel2   redis     "docker-entrypoint.s…"   sentinel2   2 minutes ago   Up 2 minutes                    
    sentinel3   redis     "docker-entrypoint.s…"   sentinel3   2 minutes ago   Up 2 minutes
    
    • 查看命令发现sentinel1 容器在启动后处于不断重启的状态,这通常表示该容器内的 Redis 哨兵服务遇到了错误并退出
    • 于是查看日志:
    [root@centos redis-cluster]# docker-compose logs sentinel1
    sentinel1  | 
    sentinel1  | *** FATAL CONFIG FILE ERROR (Redis 7.4.0) ***
    sentinel1  | Reading the configuration file, at line 2
    sentinel1  | >>> 'rt 26379'
    sentinel1  | Bad directive or wrong number of arguments
    
    • 发现 sentinel1 的配置文件在第 2 行存在语法问题。日志中提到的内容 >>> 'rt 26379',发现是配置文件拼写的错误,修改配置文件即可。
[root@centos redis-cluster]# docker-compose ps
NAME        IMAGE     COMMAND                   SERVICE     CREATED          STATUS          PORTS
redis0      redis     "docker-entrypoint.s…"   redis0      4 days ago       Up 41 minutes   
redis1      redis     "docker-entrypoint.s…"   redis1      4 days ago       Up 41 minutes   
redis2      redis     "docker-entrypoint.s…"   redis2      4 days ago       Up 41 minutes   
redis3      redis     "docker-entrypoint.s…"   redis3      4 days ago       Up 41 minutes   
redis4      redis     "docker-entrypoint.s…"   redis4      4 days ago       Up 41 minutes   
sentinel1   redis     "docker-entrypoint.s…"   sentinel1   17 minutes ago   Up 35 seconds   
sentinel2   redis     "docker-entrypoint.s…"   sentinel2   17 minutes ago   Up 17 minutes   
sentinel3   redis     "docker-entrypoint.s…"   sentinel3   17 minutes ago   Up 17 minutes 

  1. 在模拟master节点宕机时:

因为我一开始搭建的是“主从从”模式集群,再在该基础上搭建哨兵集群,结构如下:

image-20241010111723147

哨兵不直接支持级联从节点的监控(即哨兵一般不会监控从节点的从节点 - 我们所搭建的redis3和redis4),但这时我们已经搭建好了,就不打算将redis3和redis4rm,我们先将redis0 stop再start,然后发现:

当 Redis 哨兵检测到主节点 redis0 不可用时,它将 redis2 切换为新的主节点。由于 redis3redis4 原本是 redis2 的从节点,这个链条并未断裂,且由于 redis2 成为了主节点,哨兵将其下的所有从节点(包括原本的从节点的从节点)也作为它的从节点进行管理

  • redis2 成为新的主节点后,redis1redis3、和 redis4 均会被识别为 redis2直接从节点,形成多层次的直接复制。

  • 因为哨兵在切换时没有自动重设 redis3redis4 的主从关系,它们仍然保持与 redis2 的连接。

  • 我们在RDM中对redis进行info replication,观察如下:

image-20241010112416474

  • 为什么没有redis0
    • redis0 作为 redis2 的从节点重新连接时,可能还没有完成所有的复制同步和状态更新。即使 redis0 成功连接为从节点,它的状态可能还在初始化过程中,导致暂时没有出现在 redis2 的从节点列表中。当我们再次尝试稍等片刻,然后再次使用 info replication 检查,就可以看到redis0也成为了redis2slave

当我们对其中一个sentinel进行sentinel slaves jobs操作后,发现:

image-20241009200231810

image-20241009200313041

image-20241009200352044

image-20241009200428858

  • 哨兵在切换后会将所有的下层节点(包括多级从节点)作为新的主节点的从节点进行管理。因此,当你在 sentinel slaves jobs 中查询时,能看到所有属于 redis2 直接或间接从属关系的节点(即 redis1redis3redis4 等),都被列为它的从节点。

因此,为了减少不必要的麻烦,我们会简化为一层“主-从”结构,以便哨兵更高效地管理复制关系。


参考博文:
Redis 哨兵集群搭建并使用 RedisTemplate 实现读写分离

参考书籍:
《Redis核心技术与实战》

posted @ 2024-10-10 12:20  尘尘尘  阅读(41)  评论(0编辑  收藏  举报