走进Redis:哨兵集群
为什么需要哨兵
在 Redis 的主从库模式中,如果从库发生了故障,用户的操作是可以继续进行的,因为写操作是只在主库中进行的。那么,如果主库发生了故障,用户的操作将会收到影响。这时候可能会需要选择一个从库在作为主库继续服务用户的操作。Redis 提供的哨兵机制就是解决主从库模式的 Redis 服务可用性问题的。
故障转移的基本流程
哨兵发现主库下线并选出新主库的流程称为故障转移,这个过程需要解决三个问题:
- 主库真的挂了吗?(监控)
- 该选择那个从库作为主库?(选主)
- 怎么把新主库的相关信息通知给从库和客户端呢?(通知)
监控
哨兵在运行过程中周期性的给所有主从库发送 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。具体流程如下:
- 当哨兵将 master 节点标记为客观下线后,会将当前纪元(epoch,该值类似 raft 协议的 term 值)加一,表示开始一次新的 leader 选举。
- 首先会给自己投一票,然后会再次发送
is-master-down-by-addr
给其它哨兵。这个命令的使用方式如下:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>
。这里主要看 runid,确认主节点是否客观下线时,该值为 *;开始参选 Leader 时,传的参数为本节点的 runid。 - 收到命令的哨兵,如果没有同意过其他节点的
sentinel is-master-down-by-addr
命令,将同意该请求,否则拒绝。并且同意过其它节点后,该节点也不会发起投票。 - 如果该哨兵发现自己的票数已经大于等于
max(quorum, num(sentinels)/2+1)
,那么它将成为领导者。 - 如果此过程没有选举出领导者,将进入下一次选举。选举超时时间可以查看配置
failover-timeout
。
筛选
- 首先会判断从库当前的状态,过滤掉当前主观下线以及断线的节点;
- 5 秒内没有回复过哨兵节点 PING 请求的节点;
- 与主节点断连次数超过 10 次的节点。是否断连是根据配置项
down-after-milliseconds
来判断的,主从节点down-after-milliseconds
毫秒内都没有连接上,则会被记为一次断连。
打分
- 通过配置项 slave-priority 来给不同的从库设置不同的优先级。可以使用命令
info Replication
来查看该配置。如果有一个从库的优先级最高,那么该从库会直接选为新主库;否则,将会进行第二轮打分。 - 与旧主库同步程度最接近的从库得分高。在主从同步中提到过,从库会用
slave_repl_offset
来记录当前从 master 的复制进度,该配置通过info Replication
可以查看。哨兵会选出复制进度值最大的从库作为新的主库,如果多个从库复制进度并列第一,那么需要进行第三轮打分。 - ID 号最小的从库得分高。最后,哨兵会查看从库的 runId ,将 runId 最小的从库作为新主库。runId 通过命令
info Server
可以查看。
通知
当选出新主库之后,哨兵有三个角色需要通知:
- 告诉新主库它已经称为了新主库。哨兵会向目标库发送命令
slaveof no one
,收到命令后,目标库会将自己的角色( role )提升为master
。 - 告诉其它从库新主库的地址。哨兵会向其它从库发送
slaveof host port
来告诉从库新主库的地址,从库会执行replicaof
命令开始从新主库同步。 - 通知客户端主库变化。当新主库切换完成后,哨兵会在频道
+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 呢?主要有以下几个步骤:
- 连接哨兵集群。客户端初始化时,需要提供哨兵的地址,客户端会连接到第一个可用的哨兵地址。
- 连接主库。客户端给哨兵发送
SENTINEL get-master-addr-by-name <master-name>
获取主库地址,然后和主库建立连接。为了确认连接的确实是主库,客户端还需要发送info replication
命令来查看 role 是否是 master,如果不是的话就要从第一步重新开始。 - 连接从库。客户端给哨兵发送
SENTINEL replicas <master-name>
来获取从库信息。相应的,客户端也可以通过 info 命令来确认目标的角色。 - 监听主库迁移。哨兵通过 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:哨兵集群的更多相关文章
- Linux - redis哨兵集群实例
目录 Linux - redis哨兵集群实例 命令整理 配置流程 Linux - redis哨兵集群实例 命令整理 官网地址:http://redisdoc.com/ redis-cli info # ...
- helm部署Redis哨兵集群
介绍 Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现.故障自动转移.配置中心和客户端通知. 如下图: Redis Sentinel 故障转移过程: 从这 ...
- 11.Redis 哨兵集群实现高可用
作者:中华石杉 Redis 哨兵集群实现高可用 哨兵的介绍 sentinel,中文名是哨兵.哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能: 集群监控:负责监控 redis mast ...
- python连接redis哨兵集群
一.redis集群模式有多种, 哨兵模式只是其中的一种实现方式, 其原理请自行谷歌或者百度 二.python 连接 redis 哨兵集群 1. 安装redis包 pip install redis 2 ...
- redis哨兵集群搭建
下载redis jar包redis-4.0.11.tar.gz放在/data/redis目录下 解压 命令:tar -zxvf redis-4.0.11.tar.gz 解压后如图所示 在/usr/lo ...
- Redis进阶实践之十 Redis哨兵集群模式
一.引言 上一篇文章我们详细的讲解了Redis的主从集群模式,其实这个集群模式配置很简单,只需要在Slave的节点上进行配置,Master主节点的配置不需要做任何更改,但是有一 ...
- redis哨兵集群+spring boot 2.×
Ubuntu集群构建篇 redis-cli:不跟参数,默认访问localhost:6379端口,无密码登陆 redis-cli -h ${host} -p ${port} -a ${password} ...
- redis哨兵集群环境搭建
一.哨兵的介绍 哨兵(sentinal)是redis集群架构中非常重要的一个组件,主要功能如下: 集群监控,负责监控redis master和slave进程是否正常工作 消息通知,如果某个redis实 ...
- redis哨兵集群、docker入门
redis-sentinel主从复制高可用 Redis-Sentinel Redis-Sentinel是redis官方推荐的高可用性解决方案,当用redis作master-slave的高可用时,如果m ...
- 【Redis哨兵集群】
目录 开始配置主从复制 开始配置Redis Sentinel @ *** 在开始之前,我们先来看看Redis的主从复制 主从复制原理: 从服务器向主服务器发送SYNC命令. 主服务器接到SYNC命令后 ...
随机推荐
- Django序列化组件与数据批量操作与简单使用Forms组件
目录 SweetAlert前端插件 Django自带的序列化组件 批量数据操作 分页器与推导流程 Forms组件之创建 Forms组件之数据校验 Forms组件之渲染标签 Forms组件之信息展示 S ...
- MVC 调试页面路径变成 Views/Controller/Action.cshtml问题
MVC在路由里面已经写好了路径,但是调试时地址栏还是会变成 Views/Controller/Action.cshtml,导致报404错误,找不到路径. 原因可能是你将某一页面设为了起始页,导致每次运 ...
- 【Unity Shader学习笔记】Unity光照基础-漫反射光照
本代码只适用于平行光. 1.逐顶点漫反射光照 1.1漫反射光照原理 1.2代码实现 在Properties语义块中声明一个漫反射颜色属性 Properties { //漫反射参数,用于调整漫反射效果 ...
- PostgreSQL Array 数组类型与 FreeSql 打出一套【组合拳】
前言 PostgreSQL 是世界公认的功能最强大的开源数据库,除了基础数据类型 int4/int8/varchar/numeric/timestamp 等数据类型,还支持 int4[]/int8[] ...
- 【Golang】创建有配置参数的结构体时,可选参数应该怎么传?
写在前面的话 Golang中构建结构体的时候,需要通过可选参数方式创建,我们怎么样设计一个灵活的API来初始化结构体呢. 让我们通过如下的代码片段,一步一步说明基于可选参数模式的灵活 API 怎么设计 ...
- iOS全埋点解决方案-采集奔溃
前言 采集应用程序奔溃信息,主要分为以下两种场景: NSException 异常 Unix 信号异常 一.NSException 异常 NSException 异常是 Objectiv ...
- 我的第一个springboot starter
在springboot中有很多starter,很多是官方开发的,也有是个人或开源组织开发的.这些starter是用来做什么的呐? 一.认识starter 所谓的starter,在springb ...
- 开发工具-RSA加解密
更新日志 2022年6月10日 初始化链接. https://toolb.cn/rsa
- JS:自增和自减
自增自减是一元操作符运算 1.++: 前置++:先把取值,再把变量的值加1 后置++:先把变量的值加1,再取值 2.--: 前置--:先把取值,再把变量的值加1 后置--:先把变量的值加1,再取值 v ...
- BUUCTF-假如给我三天光明
假如给我三天光明 打开压缩包可以看到一个海报,下方有盲文显示,通过对照表得知 盲文翻译为kmdonowg 通过盲文翻译得到的字符串解压压缩包得到一个音频文件 使用Audacity打开,看样子应该是摩斯 ...