db-tutorial/docs/12.数据库/05.KV数据库/01.Redis/06.Redis哨兵.md

184 lines
12 KiB
Markdown
Raw Normal View History

2022-04-11 16:52:35 +08:00
---
title: Redis 哨兵
date: 2020-06-24 10:45:38
2022-06-09 15:16:02 +08:00
categories:
- 数据库
- KV数据库
- Redis
2022-06-09 15:16:02 +08:00
tags:
- 数据库
- KV数据库
- Redis
- 哨兵
2022-06-09 15:16:02 +08:00
permalink: /pages/615afe/
2022-04-11 16:52:35 +08:00
---
2020-02-25 22:35:18 +08:00
# Redis 哨兵
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
> Redis 哨兵Sentinel是 Redis 的**高可用性**Hight Availability解决方案。
>
2023-02-10 11:43:21 +08:00
> Redis 哨兵是 [Raft 算法](https://dunwu.github.io/blog/pages/4907dc/) 的具体实现。
2018-06-19 17:39:28 +08:00
2021-05-13 16:57:28 +08:00
![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200713072747.png)
2018-06-19 17:39:28 +08:00
2020-02-25 22:35:18 +08:00
## 一、哨兵简介
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
Redis 哨兵Sentinel是 Redis 的**高可用性**Hight Availability解决方案由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
2021-05-13 16:57:28 +08:00
![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200131135847.png)
2020-07-13 10:08:37 +08:00
2020-02-02 17:54:35 +08:00
Sentinel 的主要功能如下:
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
- **`监控Monitoring`** - Sentinel 不断检查主从服务器是否正常在工作。
- **`通知Notification`** - Sentinel 可以通过一个 api 来通知系统管理员或者另外的应用程序,被监控的 Redis 实例有一些问题。
- **`自动故障转移Automatic Failover`** - 如果一个主服务器下线Sentinel 会开始自动故障转移:把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,使用 Redis 服务的应用程序在连接的时候也被通知新的地址。
- **`配置提供者Configuration provider`** - Sentinel 给客户端的服务发现提供来源:对于一个给定的服务,客户端连接到 Sentinels 来寻找当前主节点的地址。当故障转移发生的时候Sentinel 将报告新的地址。
2018-06-19 17:39:28 +08:00
2020-02-25 22:35:18 +08:00
## 二、启动哨兵
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
启动一个 Sentinel 可以使用下面任意一条命令,两条命令效果完全相同。
2018-06-19 17:39:28 +08:00
2020-02-25 22:35:18 +08:00
```shell
2018-06-19 17:39:28 +08:00
redis-sentinel /path/to/sentinel.conf
redis-server /path/to/sentinel.conf --sentinel
```
2020-02-02 17:54:35 +08:00
当一个 Sentinel 启动时,它需要执行以下步骤:
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
1. 初始化服务器。
2020-07-13 10:08:37 +08:00
2. 使用 Sentinel 专用代码。
2020-02-02 17:54:35 +08:00
3. 初始化 Sentinel 状态。
2020-07-13 10:08:37 +08:00
4. 初始化 Sentinel 的主服务器列表。
5. 创建连向被监视的主服务器的网络连接。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
**Sentinel 本质上是一个运行在特殊状模式下的 Redis 服务器**。
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
Sentinel 模式下 Redis 服务器只支持 `PING`、`SENTINEL`、`INFO`、`SUBSCRIBE`、`UNSUBSCRIBE`、`PSUBSCRIBE`、`PUNSUBSCRIBE` 七个命令。
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
创建连向被监视的主服务器的网络连接Sentinel 将成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息。对于每个被 Sentinel 监视的主服务器Sentinel 会创建两个连向主服务器的异步网络:
- 命令连接:专门用于向主服务器发送命令,并接受命令回复。
- 订阅连接:专门用于订阅主服务器的 `__sentinel__:hello` 频道。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
## 三、监控
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
### 检测服务器状态
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
> **Sentinel 向 Redis 服务器发送 `PING` 命令,检查其状态**。
2018-06-19 17:39:28 +08:00
2020-02-09 23:34:42 +08:00
默认情况下,**每个** `Sentinel` 节点会以 **每秒一次** 的频率对 `Redis` 节点和 **其它** 的 `Sentinel` 节点发送 `PING` 命令,并通过节点的 **回复** 来判断节点是否在线。
2020-07-13 10:08:37 +08:00
- **主观下线****主观下线** 适用于所有 **主节点** 和 **从节点**。如果在 `down-after-milliseconds` 毫秒内,`Sentinel` 没有收到 **目标节点** 的有效回复,则会判定 **该节点** 为 **主观下线**。
- **客观下线****客观下线** 只适用于 **主节点**。当 `Sentinel` 将一个主服务器判断为主管下线后,为了确认这个主服务器是否真的下线,会向同样监视这一主服务器的其他 Sentinel 询问,看它们是否也认为主服务器已经下线。当足够数量的 Sentinel 认为主服务器已下线,就判定其为客观下线,并对其执行故障转移操作。
- `Sentinel` 节点通过 `sentinel is-master-down-by-addr` 命令,向其它 `Sentinel` 节点询问对该节点的 **状态判断**。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
### 获取服务器信息
2018-06-19 17:39:28 +08:00
2020-02-25 22:35:18 +08:00
> **Sentinel 向主服务器发送 `INFO` 命令,获取主服务器及它的从服务器信息**。
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
- **获取主服务器信息** - Sentinel **默认**会以**每十秒一次**的频率,通过命令连接**向被监视的主服务器发送 `INFO` 命令,并通过分析 `INFO` 命令的回复来获取主服务器的当前信息**。
- 主服务自身信息:包括 run_id 域记录的服务器运行 ID以及 role 域记录的服务器角色
- 主服务的从服务器信息:包括 IP 地址和端口号
2020-02-02 17:54:35 +08:00
- **获取从服务器信息** - 当 Sentinel 发现主服务器有新的从服务器出现时Sentinel 除了会为这个新的从服务器创建相应的实例结构之外Sentinel 还会创建连接到从服务器的命令连接和订阅连接。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
## 四、通知
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
对于每个与 Sentinel 连接的服务器Sentinel 既会向服务器的 `__sentinel__:hello` 频道发送消息,也会订阅服务器的 `__sentinel__:hello` 频道的消息。
2018-06-19 17:39:28 +08:00
2021-05-13 16:57:28 +08:00
![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200131153842.png)
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
### 向服务器发送消息
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
在默认情况下Sentinel 会以每两秒一次的频率,通过命令向所有被监视的主服务器和从服务器发送以下格式的命令。
2018-06-19 17:39:28 +08:00
```
2020-02-02 17:54:35 +08:00
PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
2018-06-19 17:39:28 +08:00
```
2020-02-02 17:54:35 +08:00
这条命令向服务器的 `__sentinel__:hello` 频道发送一条消息。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
### 接收服务器的消息
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
当 Sentinel 与一个主服务器或从服务器建立起订阅连接后Sentinel 就会通过订阅连接,向服务器发送以下命令:`SUBSCRIBE __sentinel__:hello`。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
Sentinel 对 `__sentinel__:hello` 频道的订阅会一直持续到 Sentinel 与服务器断开连接为止。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
## 五、选举 Leader
2018-06-19 17:39:28 +08:00
2020-02-09 02:18:58 +08:00
> Redis Sentinel 系统选举 Leader 的算法是 [Raft](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 的实现。
>
2023-02-10 11:43:21 +08:00
> Raft 是一种共识性算法,想了解其原理,可以参考 [深入剖析共识性算法 Raft](https://dunwu.github.io/blog/pages/4907dc/)。
2018-06-19 17:39:28 +08:00
2020-07-13 10:08:37 +08:00
**当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头的 Sentinel并由领头 Sentinel 对下线主服务器执行故障转移操作**。
2018-06-19 17:39:28 +08:00
2020-02-02 17:54:35 +08:00
所有在线 Sentinel 都有资格被选为 Leader。
2018-06-19 17:39:28 +08:00
2020-02-09 23:34:42 +08:00
每个 `Sentinel` 节点都需要 **定期执行** 以下任务:
1每个 `Sentinel`**每秒钟** 一次的频率,向它所知的 **主服务器**、**从服务器** 以及其他 `Sentinel` **实例** 发送一个 `PING` 命令。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce61df44c4d?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
2如果一个 **实例**`instance`)距离 **最后一次** 有效回复 `PING` 命令的时间超过 `down-after-milliseconds` 所指定的值,那么这个实例会被 `Sentinel` 标记为 **主观下线**。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce61dc739de?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
3如果一个 **主服务器** 被标记为 **主观下线**,那么正在 **监视** 这个 **主服务器** 的所有 `Sentinel` 节点,要以 **每秒一次** 的频率确认 **主服务器** 的确进入了 **主观下线** 状态。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce647a39535?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
4如果一个 **主服务器** 被标记为 **主观下线**,并且有 **足够数量** 的 `Sentinel`(至少要达到 **配置文件** 指定的数量)在指定的 **时间范围** 内同意这一判断,那么这个 **主服务器** 被标记为 **客观下线**。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce647c2583e?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
5在一般情况下 每个 `Sentinel` 会以每 `10` 秒一次的频率,向它已知的所有 **主服务器** 和 **从服务器** 发送 `INFO` 命令。当一个 **主服务器** 被 `Sentinel` 标记为 **客观下线** 时,`Sentinel` 向 **下线主服务器** 的所有 **从服务器** 发送 `INFO` 命令的频率,会从 `10` 秒一次改为 **每秒一次**。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce6738a30db?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
6`Sentinel` 和其他 `Sentinel` 协商 **主节点** 的状态,如果 **主节点** 处于 `SDOWN` 状态,则投票自动选出新的 **主节点**。将剩余的 **从节点** 指向 **新的主节点** 进行 **数据复制**。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce676a95a54?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
7当没有足够数量的 `Sentinel` 同意 **主服务器** 下线时, **主服务器** 的 **客观下线状态** 就会被移除。当 **主服务器** 重新向 `Sentinel``PING` 命令返回 **有效回复** 时,**主服务器** 的 **主观下线状态** 就会被移除。
![img](https://user-gold-cdn.xitu.io/2018/8/22/16560ce6759c1cb3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
> 注意:一个有效的 `PING` 回复可以是:`+PONG`、`-LOADING` 或者 `-MASTERDOWN`。如果 **服务器** 返回除以上三种回复之外的其他回复,又或者在 **指定时间** 内没有回复 `PING` 命令, 那么 `Sentinel` 认为服务器返回的回复 **无效**`non-valid`)。
2020-02-02 17:54:35 +08:00
## 六、故障转移
2019-08-20 17:40:45 +08:00
2020-02-09 23:34:42 +08:00
在选举产生出 Sentinel Leader 后Sentinel Leader 将对已下线的主服务器执行故障转移操作。操作含以下三个步骤:
2020-07-13 10:08:37 +08:00
(一)**选出新的主服务器**
故障转移第一步,是 Sentinel Leader 在已下线主服务属下的所有从服务器中,挑选一个状态良好、数据完整的从服务器。然后,向这个从服务器发送 `SLAVEOF no one` 命令,将其转换为主服务器。
Sentinel Leader 如何选出新的主服务器:
- 删除列表中所有处于下线或断线状态的从服务器。
- 删除列表中所有最近五秒没有回复过 Sentinel Leader 的 INFO 命令的从服务器。
- 删除所有与已下线主服务器连接断开超过 `down-after-milliseconds` \* 10 毫秒的从服务器(`down-after-milliseconds` 指定了判断主服务器下线所需的时间)。
- 之后, Sentinel Leader 先选出优先级最高的从服务器;如果优先级一样高,再选择复制偏移量最大的从服务器;如果结果还不唯一,则选出运行 ID 最小的从服务器。
(二)**修改从服务器的复制目标**
选出新的主服务器后Sentinel Leader 会向所有从服务器发送 `SLAVEOF` 命令,让它们去复制新的主服务器。
2020-02-09 23:34:42 +08:00
2020-07-13 10:08:37 +08:00
(三)**将旧的主服务器变为从服务器**
2020-02-25 22:35:18 +08:00
2020-07-13 10:08:37 +08:00
Sentinel Leader 将旧的主服务器标记为从服务器。当旧的主服务器重新上线Sentinel 会向它发送 SLAVEOF 命令,让其成为从服务器。
2020-02-25 22:35:18 +08:00
2019-08-20 17:40:45 +08:00
## 参考资料
2019-08-22 09:02:39 +08:00
2020-02-02 17:54:35 +08:00
- **官网**
- [Redis 官网](https://redis.io/)
2020-06-24 10:45:38 +08:00
- [Redis github](https://github.com/antirez/redis)
- [Redis 官方文档中文版](http://redis.cn/)
2020-02-02 17:54:35 +08:00
- **书籍**
- [《Redis 实战》](https://item.jd.com/11791607.html)
- [《Redis 设计与实现》](https://item.jd.com/11486101.html)
2020-06-24 10:45:38 +08:00
- **教程**
- [Redis 命令参考](http://redisdoc.com/)
2020-02-02 17:54:35 +08:00
- **文章**
- [渐进式解析 Redis 源码 - 哨兵 sentinel](http://www.web-lovers.com/redis-source-sentinel.html)
2023-06-27 23:11:00 +08:00
- [深入剖析 Redis 系列(二) - Redis 哨兵模式与高可用集群](https://juejin.im/post/5b7d226a6fb9a01a1e01ff64)