在 Redis 的主从库模式中,如果从库发生了故障,用户的操作是可以继续进行的,因为写操作是只在主库中进行的。那么,如果主库发生了故障,用户的操作将会收到影响。这时候可能会需要选择一个从库在作为主库继续服务用户的操作。Redis 提供的哨兵机制就是解决主从库模式的 Redis 服务可用性问题的。
哨兵发现主库下线并选出新主库的流程称为故障转移,这个过程需要解决三个问题:
哨兵在运行过程中周期性的给所有主从库发送 PING 命令,以此检测它们是否正常运行。如果某个实例对 PING 命令的没有在 down-after-milliseconds 应答,那么,哨兵会把它标记为“ 主观下线 ”。
哨兵不会对主观下线的从库做额外的处理,如果是主库主观下线,那么哨兵会进行后续的选主和通知操作,这些操作会有额外的计算和通信开销。为了减少误判,哨兵通常会采用集群部署。当一个哨兵将 master 标记为主观下线后,会和其它哨兵实例通过命令 SENTINEL is-master-down-by-addr 交流,如果有大于 quorum 个哨兵确认 master 已下线,则该 master 会被标记为” 客观下线” ;否则,会重新将 master 标记为上线状态。
:bulb: quorum 通过 sentinel.conf 配置得到,和哨兵集群中实例的数量有关。例如,若共有 3 个实例,则该值可设置为 2 ,最好将该值设置为 $N/2+1$ 。该值越小,判断 master 客观下线的条件越宽松;反之则判断 master 客观下线的条件越严格。通常哨兵集群中实例的数量为奇数,避免出现应答下线和未下线数量相同的情况。
选新主库的过程大致可以分为以下几个步骤:
哨兵 Leader 是本次故障转移的执行者,每个哨兵都有机会成为 Leader。具体流程如下:
当选出新主库之后,哨兵有三个角色需要通知:
上面讨论主从切换的时候有提到哨兵集群来减少主库客观下线误判的可能性。哨兵监控一个 master 节点是通过下面这个命令来完成的:
sentinel monitor 这个命令中并没有指定其它哨兵的地址信息,那么哨兵是如何组成一个集群的呢?
哨兵成功和主节点建立连接之后,会在主节点上创建一个名为 “ sentinel :hello” 的频道,然后会将自己的地址端口等信息发布到该频道,其它哨兵就可以从这个频道获取监控同一个主节点的哨兵信息,互相建立网络连接,形成一个集群。
:bulb: 我们可以用 redis-cli 连接上主节点,然后用命令 psubscribe * 监听主节点上的所有频道,会看到哨兵不断在 __sentienl__:hello 频道发送自己的信息。
redis 主库会保存从库的信息,哨兵会向主库发送 INFO 命令来获取从库列表。哨兵就可以根据从库列表的地址信息和每个从库建立连接,然后监控从库的状态。
哨兵获取从库信息主要是 INFO 命令查看主库的 replication 信息,典型的一个 replication 信息如下所示:
127.0.0.1:6380> info replication# Replicationrole:masterconnected_slaves:2slave0:ip=172.26.0.3,port=6379,state=online,offset=217874,lag=0slave1:ip=172.26.0.2,port=6379,state=online,offset=217874,lag=0master_failover_state:no-failovermaster_replid:51567b12a9c1ba1d82846a8fb8fd84404b60eaf8master_replid2:0baa276d98298739b2e0755640fd5b50d2828b26master_repl_offset:217874second_repl_offset:17993repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:429repl_backlog_histlen:217446从信息里可以看到主库的 role 为 master ,已连接的从库数量(connected_slaves)为 2,然后 slave0 和 slave1 就是从库的信息。
哨兵会定期给主库和从库发送 PING 命令检测网络状态,如果超时未应答就会标记为主观下线,如果主观下线的是主库,就会开启故障转移流程。
客户端如何访问哨兵集群监控的 redis-server 呢?主要有以下几个步骤:
可以使用以下 docker-compose 来简单模拟故障迁移的实验:
version: "3"services: redis-master: image: redis:7 ports: - "16379:6379" container_name: "redis-master" command: redis-server networks: - sentinel-network redis-slave-1: image: redis:7 ports: - "6380:6379" container_name: "redis-slave-1" command: redis-server --replicaof redis-master 6379 depends_on: - redis-master networks: - sentinel-network redis-slave-2: image: redis:7 ports: - "6381:6379" container_name: "redis-slave-2" command: redis-server --replicaof redis-master 6379 depends_on: - redis-master networks: - sentinel-network redis-sentinel: image: bitnami/redis-sentinel:latest environment: - REDIS_MASTER_HOST=redis-master - REDIS_SENTINEL_QUORUM=2 - REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=10000 depends_on: - redis-master - redis-slave-1 ports: - '26379-26381:26379' networks: - sentinel-networknetworks: sentinel-network:使用命令 docker-compose up --scale redis-sentinel=3 来启动 docker-compose。启动之后会打出如下的日志:
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 * Sentinel new configuration saved on diskredis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # Sentinel ID is 787487fa6116b997caa0a44b011793b58e265a54redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # +monitor master mymaster 172.27.0.2 6379 quorum 2redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.827 * +slave slave 172.27.0.3:6379 172.27.0.3 6379 @ mymaster 172.27.0.2 6379redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.840 * Sentinel new configuration saved on diskredis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.840 * +slave slave 172.27.0.4:6379 172.27.0.4 6379 @ mymaster 172.27.0.2 6379日志表示这样一个流程:哨兵初始化完成 ⇒ 监控主库 ⇒ 监控从库。
此时,如果连接上主库,然后订阅 __sentinel__:hello 频道,可以看到如下的消息:
集群内的哨兵都在往 __sentinel__:hello 发送自己的服务信息。
可以使用命令 docker stop redis-master 来模拟主库下线的情况,在执行这个命令之前可以先连到哨兵节点 redis-cli -p 26379 ,然后用命令 psubscribe * 来订阅哨兵的频道,这样模拟主库下线时就能看到哨兵通过频道通知客户端的消息了:
Redis 哨兵的相关原理暂时告一段落,欢迎大家交流。
| 留言与评论(共有 0 条评论) “” |