为什么需要哨兵

在 Redis 的主从库模式中,如果从库发生了故障,用户的操作是可以继续进行的,因为写操作是只在主库中进行的。那么,如果主库发生了故障,用户的操作将会收到影响。这时候可能会需要选择一个从库在作为主库继续服务用户的操作。Redis 提供的哨兵机制就是解决主从库模式的 Redis 服务可用性问题的。

故障转移的基本流程

哨兵发现主库下线并选出新主库的流程称为故障转移,这个过程需要解决三个问题:

  1. 主库真的挂了吗?(监控)
  2. 该选择那个从库作为主库?(选主)
  3. 怎么把新主库的相关信息通知给从库和客户端呢?(通知)

监控

哨兵在运行过程中周期性的给所有主从库发送 PING 命令,以此检测它们是否正常运行。如果某个实例对 PING 命令的没有在down-after-milliseconds 应答,那么,哨兵会把它标记为“主观下线”。

哨兵不会对主观下线的从库做额外的处理,如果是主库主观下线,那么哨兵会进行后续的选主和通知操作,这些操作会有额外的计算和通信开销。为了减少误判,哨兵通常会采用集群部署。当一个哨兵将 master 标记为主观下线后,会和其它哨兵实例通过命令 SENTINEL is-master-down-by-addr 交流,如果有大于 quorum 个哨兵确认 master 已下线,则该 master 会被标记为”客观下线”;否则,会重新将 master 标记为上线状态。

quorum 通过 sentinel.conf 配置得到,和哨兵集群中实例的数量有关。例如,若共有 3 个实例,则该值可设置为 2 ,最好将该值设置为 $N/2+1$。该值越小,判断 master 客观下线的条件越宽松;反之则判断 master 客观下线的条件越严格。通常哨兵集群中实例的数量为奇数,避免出现应答下线和未下线数量相同的情况。

选主

选新主库的过程大致可以分为以下几个步骤:

哨兵 Leader 选举

哨兵 Leader 是本次故障转移的执行者,每个哨兵都有机会成为 Leader。具体流程如下:

  1. 当哨兵将 master 节点标记为客观下线后,会将当前纪元(epoch,该值类似 raft 协议的 term 值)加一,表示开始一次新的 leader 选举。
  2. 首先会给自己投一票,然后会再次发送 is-master-down-by-addr 给其它哨兵。这个命令的使用方式如下:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>。这里主要看 runid,确认主节点是否客观下线时,该值为 *;开始参选 Leader 时,传的参数为本节点的 runid。
  3. 收到命令的哨兵,如果没有同意过其他节点的sentinel is-master-down-by-addr命令,将同意该请求,否则拒绝。并且同意过其它节点后,该节点也不会发起投票。
  4. 如果该哨兵发现自己的票数已经大于等于max(quorum, num(sentinels)/2+1),那么它将成为领导者。
  5. 如果此过程没有选举出领导者,将进入下一次选举。选举超时时间可以查看配置 failover-timeout

筛选

  1. 首先会判断从库当前的状态,过滤掉当前主观下线以及断线的节点;
  2. 5 秒内没有回复过哨兵节点 PING 请求的节点;
  3. 与主节点断连次数超过 10 次的节点。是否断连是根据配置项 down-after-milliseconds 来判断的,主从节点 down-after-milliseconds 毫秒内都没有连接上,则会被记为一次断连。

打分

  1. 通过配置项 slave-priority 来给不同的从库设置不同的优先级。可以使用命令 info Replication 来查看该配置。如果有一个从库的优先级最高,那么该从库会直接选为新主库;否则,将会进行第二轮打分。
  2. 与旧主库同步程度最接近的从库得分高。在主从同步中提到过,从库会用 slave_repl_offset 来记录当前从 master 的复制进度,该配置通过 info Replication 可以查看。哨兵会选出复制进度值最大的从库作为新的主库,如果多个从库复制进度并列第一,那么需要进行第三轮打分。
  3. ID 号最小的从库得分高。最后,哨兵会查看从库的 runId ,将 runId 最小的从库作为新主库。runId 通过命令 info Server 可以查看。

通知

当选出新主库之后,哨兵有三个角色需要通知:

  1. 告诉新主库它已经称为了新主库。哨兵会向目标库发送命令 slaveof no one ,收到命令后,目标库会将自己的角色( role )提升为master
  2. 告诉其它从库新主库的地址。哨兵会向其它从库发送 slaveof host port 来告诉从库新主库的地址,从库会执行 replicaof 命令开始从新主库同步。
  3. 通知客户端主库变化。当新主库切换完成后,哨兵会在频道 +switch-master 中发送消息,通知外部客户端新主库地址。

哨兵集群

上面讨论主从切换的时候有提到哨兵集群来减少主库客观下线误判的可能性。哨兵监控一个 master 节点是通过下面这个命令来完成的:

sentinel monitor <master-name> <ip> <redis-port> <quorum>

这个命令中并没有指定其它哨兵的地址信息,那么哨兵是如何组成一个集群的呢?

基于 pub/sub 机制的哨兵集群

哨兵成功和主节点建立连接之后,会在主节点上创建一个名为 “sentinel:hello” 的频道,然后会将自己的地址端口等信息发布到该频道,其它哨兵就可以从这个频道获取监控同一个主节点的哨兵信息,互相建立网络连接,形成一个集群。

我们可以用 redis-cli 连接上主节点,然后用命令psubscribe * 监听主节点上的所有频道,会看到哨兵不断在 __sentienl__:hello 频道发送自己的信息。

获取从库信息

redis 主库会保存从库的信息,哨兵会向主库发送 INFO 命令来获取从库列表。哨兵就可以根据从库列表的地址信息和每个从库建立连接,然后监控从库的状态。

哨兵获取从库信息主要是INFO 命令查看主库的 replication 信息,典型的一个 replication 信息如下所示:

127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.26.0.3,port=6379,state=online,offset=217874,lag=0
slave1:ip=172.26.0.2,port=6379,state=online,offset=217874,lag=0
master_failover_state:no-failover
master_replid:51567b12a9c1ba1d82846a8fb8fd84404b60eaf8
master_replid2:0baa276d98298739b2e0755640fd5b50d2828b26
master_repl_offset:217874
second_repl_offset:17993
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:429
repl_backlog_histlen:217446

从信息里可以看到主库的 role 为 master ,已连接的从库数量(connected_slaves)为 2,然后 slave0 和 slave1 就是从库的信息。

哨兵会定期给主库和从库发送 PING 命令检测网络状态,如果超时未应答就会标记为主观下线,如果主观下线的是主库,就会开启故障转移流程。

客户端访问 redis-server

客户端如何访问哨兵集群监控的 redis-server 呢?主要有以下几个步骤:

  1. 连接哨兵集群。客户端初始化时,需要提供哨兵的地址,客户端会连接到第一个可用的哨兵地址。
  2. 连接主库。客户端给哨兵发送 SENTINEL get-master-addr-by-name <master-name> 获取主库地址,然后和主库建立连接。为了确认连接的确实是主库,客户端还需要发送 info replication 命令来查看 role 是否是 master,如果不是的话就要从第一步重新开始。
  3. 连接从库。客户端给哨兵发送 SENTINEL replicas <master-name>来获取从库信息。相应的,客户端也可以通过 info 命令来确认目标的角色。
  4. 监听主库迁移。哨兵通过 pub/sub 来通知客户端集群中的事件。哨兵提供的订阅频道很多,具体可以查看https://redis.io/docs/manual/sentinel/#pubsub-messages 。客户端使用命令 psubscribe * 来订阅所有的频道,来了解主从切换的进度。当频道 switch-master 有新消息时,表示新主库已经切换完成。

实验

可以使用以下 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-network
networks:
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 disk
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # Sentinel ID is 787487fa6116b997caa0a44b011793b58e265a54
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # +monitor master mymaster 172.27.0.2 6379 quorum 2
redis-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 6379
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.840 * Sentinel new configuration saved on disk
redis-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 哨兵的相关原理暂时告一段落,欢迎大家交流。

走进Redis:哨兵集群的更多相关文章

  1. Linux - redis哨兵集群实例

    目录 Linux - redis哨兵集群实例 命令整理 配置流程 Linux - redis哨兵集群实例 命令整理 官网地址:http://redisdoc.com/ redis-cli info # ...

  2. helm部署Redis哨兵集群

    介绍 Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现.故障自动转移.配置中心和客户端通知. 如下图: Redis Sentinel 故障转移过程: 从这 ...

  3. 11.Redis 哨兵集群实现高可用

    作者:中华石杉 Redis 哨兵集群实现高可用 哨兵的介绍 sentinel,中文名是哨兵.哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能: 集群监控:负责监控 redis mast ...

  4. python连接redis哨兵集群

    一.redis集群模式有多种, 哨兵模式只是其中的一种实现方式, 其原理请自行谷歌或者百度 二.python 连接 redis 哨兵集群 1. 安装redis包 pip install redis 2 ...

  5. redis哨兵集群搭建

    下载redis jar包redis-4.0.11.tar.gz放在/data/redis目录下 解压 命令:tar -zxvf redis-4.0.11.tar.gz 解压后如图所示 在/usr/lo ...

  6. Redis进阶实践之十 Redis哨兵集群模式

    一.引言             上一篇文章我们详细的讲解了Redis的主从集群模式,其实这个集群模式配置很简单,只需要在Slave的节点上进行配置,Master主节点的配置不需要做任何更改,但是有一 ...

  7. redis哨兵集群+spring boot 2.×

    Ubuntu集群构建篇 redis-cli:不跟参数,默认访问localhost:6379端口,无密码登陆 redis-cli -h ${host} -p ${port} -a ${password} ...

  8. redis哨兵集群环境搭建

    一.哨兵的介绍 哨兵(sentinal)是redis集群架构中非常重要的一个组件,主要功能如下: 集群监控,负责监控redis master和slave进程是否正常工作 消息通知,如果某个redis实 ...

  9. redis哨兵集群、docker入门

    redis-sentinel主从复制高可用 Redis-Sentinel Redis-Sentinel是redis官方推荐的高可用性解决方案,当用redis作master-slave的高可用时,如果m ...

  10. 【Redis哨兵集群】

    目录 开始配置主从复制 开始配置Redis Sentinel @ *** 在开始之前,我们先来看看Redis的主从复制 主从复制原理: 从服务器向主服务器发送SYNC命令. 主服务器接到SYNC命令后 ...

随机推荐

  1. CSS基础学习(一)

    1.设置背景颜色:background-color 例:background-color:#d0e4fe;或background-color:blue; 2.字体颜色·:color 例:color:r ...

  2. 一文学完Linux常用命令

    一.Linux 终端命令格式 1.终端命令格式 完整版参考链接:Linux常用命令完整版 command [-options] [parameter] 说明: command : 命令名,相应功能的英 ...

  3. 解决 AMD 笔记本不插电源时屏幕偏暗的问题

    办法:关掉显卡设置里的 Vari-Bright 选项 最近换了锐龙版的笔记本,用着还不错,就是不插电源时看屏幕亮度不太适应,整体偏暗,有点费眼,差点就觉得 AMD 不 Yes 了.然后网上一顿找,发现 ...

  4. 白嫖Azure与体验GoLand远程开发

    前言 近期因为有本地开发远程使用Linux编译部署的需求,而虚拟机的性能实在是不敢恭维,WSL的坑之前也踩过(没有systemd等),故考虑使用SSH连接云服务器开发. 目前VSCode提出了Remo ...

  5. wsl2环境搭建

    序言 我电脑配置不高,开虚拟机跑linux总觉得太卡.最近才了解到windows早就上了wsl2--一款较为轻量的虚拟机软件.所以本篇博客偏笔记向,存粹记录以便多次使用. 环境 宿主机windows1 ...

  6. 【Openxml】颜色变化属性计算

    Openxml的颜色变化属性 目前Openxml存在颜色变化属性如下: 参数 说明 Hue 色调(色相) HueModulate 色调调制,百分比 HueOffset 色调偏移量,角度值 Satura ...

  7. 【python基础】第02回 计算机基础2

    上节内容回顾 1.绝对路径与相对路径 1.路径的概念 用来标识资源的位置 2.绝对路径 类似于全球GPS定位(给到任何人都可以顺利的找到相应的资源) eg: D:\aaa\a.txt 3.相对路径 需 ...

  8. python小题目练习(十)

    题目:根据生日判断星座 需求:实现如下图所示结果 代码展示: """Author:mllContent:根据生日判断星座Date:2020-11-23"&quo ...

  9. Proxmox6.2简单配置

    刻录: 使用rufus+GPT+DD方式写入U盘 一.更换国内源: 1)删除企业源 mv /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/so ...

  10. elastic-job和spring cloud版本冲突2

    ***************************APPLICATION FAILED TO START*************************** Description: An at ...