在 Redis 主从架构中,Slave,Master 挂掉了,如何保证可用性,实现继续读写 Redis。

1 哨兵

Sentinel 哨兵是用于监控 Redis 集群中 Master 状态的工具,是 Redis 高可用解决方案,哨兵可以监视一个或者多个 Redis Master 服务,以及这些 Master 服务的所有 Slave 服务;当某个 Master 服务宕机后,会把这个 Master 下的某个 Slave 服务升级为 Master 来替代已宕机的 Master 继续工作。

1.1 配置哨兵

打开安装 Redis 时解压的文件夹,里面有一个 sentinel.conf 文件,将该文件移动到相应的安装 Redis 目录中。然后修改一下配置:

# 取消保护模式,当Redis暴露在公网中,启动保护模式后,需要添加允许节点白名单才能访问
protected-mode no

# 哨兵启动的端口
port 26379

# 哨兵启动后,在后台运行
daemonize yes

# 哨兵日志文件
logfile /usr/local/redis/sentinel/redis-sentinel.log

# 哨兵工作空间
dir /usr/local/redis/sentinel

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# 设置 Master 节点,<quorum> 是指只需 <quorum> 台哨兵认为 Master 宕机了,就触发替代故障转移操作,将从节点变成 Master
sentinel monitor seieiMaster 192.168.191.135 6379 2

# 密码
sentinel auth-pass seieiMaster 123456

# Master 多长时间段没响应,哨兵就认为其宕机
sentinel down-after-milliseconds seieiMaster 30000

# 故障转移操作结束后,其它节点需要与新的 Master 做一次数据同步。
# 此时同步时,可以并行同步操作的节点个数
sentinel parallel-syncs seieiMaster 1

# 故障转移的最大操作时间,如果超过该时间,就由另一个节点接替故障转移操作
sentinel failover-timeout seieiMaster 180000

注意需要在防火墙中开放对应的端口,如 26379

配置了哨兵模式,就无需在 Redis 的核心配置文件中设置 Replication 配置(除了 masterauth 属性),因为就算设置了 Replication,当启动了哨兵模式后,核心配置文件对应的 Replication 配置都会被修改,一切以哨兵的配置文件为准。
测试的时候我设置了三台虚拟机 A、B、C,A 为 Master,其余为 Slave,这时使用 tail -f /usr/local/redis/sentinel/redis-sentinel.log 查看哨兵日志,然后关闭 A 的 Redis,此时就触发替代故障转移操作,然后 C 虚拟机的 Redis 就会变成 Master,B 虚拟机的 Redis 的 Master 就会修改成 C 虚拟机中的 Redis。再将 A 的 Redis 重启,发现 A 的角色变成了 Slave。
最后将所有的 Redis 重启,发现 C 依旧是 Master 角色,而其他虚拟机是 Slave 角色,打开对应的哨兵配置文件,发现它已经被修改了 sentinel monitor <master-name> <ip> <redis-port> <quorum> 这条配置信息。

注意,如果没有设置 masterauth 属性,上面会出现 原 Master 恢复后不同步的问题,即当虚拟机 A 的 Redis 重启成为 Slave 后,输入 info replication 命令查看它的同步状态是不成功(master_link_status:down),这是因为一开始 A 扮演的角色是 Master,并没有设置它的核心文件 masterauth 属性,而哨兵故障转移操作的时候也无法为其修改 masterauth 属性,从而导致它成为 Slave 时,无法连接到新 Master。
所以在配置哨兵模式时,需要在所有的 Redis 核心配置文件中配置 masterauth 属性(统一所有的密码)

1.2 SpringBoot 整合哨兵模式

yml 文件中配置:

spring:
  redis:
    # 单主机模式
    # host: 192.168.13.128
    # port: 6379
    # password: 123456
    # database: 0 # 使用索引为0 的数据库
    # 哨兵模式
    database: 0
    password: 123456
    sentinel:
      # 在哨兵配置文件中设定 Master 昵称
      master: seieiMaster
      # 所有哨兵对应的地址
      nodes: 192.168.253.4:26379,192.168.253.5:26379,192.168.253.6:26379

2 Redis 集群

之前的一主二从、哨兵模式,它们其实也就是一种集群,只是限于读取方面,提高读的并发,毕竟在正常情况下,用户的读写操作比例是八二开。但单个 Master 容量有限,数据达到一定程度也会有瓶颈,这时候可以通过水平扩展为多个 master-slave 成为多主多从集群。
构建 Redis 集群,最经典的 Redis 集群配备是:3个节点作为 Master,此外每个 Master 都配置一个 Slave,即整个集群需要6个节点,称为 三主三从
Redis 的集群模式其实集合 主从复制哨兵 的功能,当某一台主节点挂掉后,其对应的从节点会接替它作为新的主节点。

当主节点和从节点都关闭之后,此后只打开从节点,该从节点不会变为主节点

在构建集群之前,需要先做一下行为:

  • 将 Redis 关闭,将 rdb 等文件删除清空
  • 开放 16379 端口
  • 在核心配置文件配置好 masterauth 属性,删除 replicaof 属性
  • 关闭所有哨兵

在 Redis 的核心配置文件 redis.conf 配置:

# 开启集群模式
cluster-enabled yes

# 每个集群节点需要有一个配置文件,这个文件用于存储集群下的集群状态等信息包括其它节点的信息,这个文件由 Redis 维护,如果需要重新创建集群,就需要将这个文件删掉既可
cluster-config-file nodes-6379.conf

# 超过时间,超时则认为 Master 宕机,随后主备切换
cluster-node-timeout 5000

# 开启 AOF 持久化模式
appendonly yes

配置好之后,就可以重启 Redis,全部 Redis 重启之后,在任意一台服务器中输入以下命令开启集群模式:

redis-cli -a password --cluster create ip1:prot1 ip2:port2 ip3:port3 ip4:port4 ip5:port5 ip6:port6 --cluster-replicas 1

其中 --cluster-replicas 1 表示主节点与节点的比例是1,即一台主节点对应一台节点。如果建立集群成功之后,Redis 会自动分配三组主从节点组,输入以下命令可以查询到对应的集群信息:

redis-cli -a password --cluster check ip:port

输出信息如下,它会显示主从信息,数据槽信息:

192.168.253.5:6379 (790a8840...) -> 1 keys | 5462 slots | 1 slaves.
192.168.253.4:6379 (060bdeb5...) -> 1 keys | 5461 slots | 1 slaves.
192.168.253.6:6379 (2b07958f...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.253.5:6379)
M: 790a884008f87aa988b1a6f1ed97c3152915b1a9 192.168.253.5:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: ca0d95ea1dbe587fdd6ac52c2360315f36844d6b 192.168.253.10:6379
   slots: (0 slots) slave
   replicates 790a884008f87aa988b1a6f1ed97c3152915b1a9
S: c12e80359b13d74a1640cc5dbd69e1edaa9af37d 192.168.253.8:6379
   slots: (0 slots) slave
   replicates 060bdeb5de3025feaf75188ce26060c789fdbf6a
M: 060bdeb5de3025feaf75188ce26060c789fdbf6a 192.168.253.4:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 3f0b3618d963449b5389c0ccb942747a958de636 192.168.253.7:6379
   slots: (0 slots) slave
   replicates 2b07958f4f523442d2beffd6a41a5b9ddd42f18c
M: 2b07958f4f523442d2beffd6a41a5b9ddd42f18c 192.168.253.6:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

最后使用以下命令进入到 Redis 客户端的集群模式:

redis-cli -a password -c [-h host -p port]

进入集群模式客户端后,可以使用以下命令获取信息

  • cluster info:查看集群的信息,获取集群运作是否正常,槽节点的总数,正常运行的槽节点总数,不正常运行的槽节点总数,主从的对数等相关信息
  • cluster nodes:查看各个节点信息

2.1 slot 槽节点

上面输入 --cluster check 命令和启动集群时都会出现 slot 槽节点这个概念,它其实就是用于存储数据的,只有主节点才有,从节点没有。如上面 --cluster check 输出的信息显示,一个三主三从的集群模式,一共会有 16384 个槽节点,它们会平均分配给各个主节点,如 192.168.253.4 分配了 0-5460 总共 5461 个槽节点,192.168.253.5 分配了 5461-10922 总共 5462 个槽节点,192.168.253.6 分配了 10923-16383 总共 5461 个槽节点。
它存储的方式是:根据设置数据的 Key 值进行一次一致性哈希求值,然后对这个哈希值进行 16384 求模,获取到的数值对应索引就会存储到相应的槽节点中。在使用 Redis 客户端进行 setget 操作的时候,就可能会出现 Master 的切换转移从而获取对应的数据,不过使用 keys * 这样的命令就不会出现 Master 的切换转移,相应的只会获取当前对应 Master 的所有 Key 值。

2.3 SpringBoot 整合集群

spring:
  redis:
  	# 集群模式
    password: 123456
    cluster:
      # 所有 Redis 地址及端口
      nodes:  192.168.253.4:6379,192.168.253.5:6379,192.168.253.6:6379,192.168.253.7:6379,192.168.253.8:6379,192.168.253.10:6379