2
2
3
3
## 哨兵的介绍
4
4
sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
5
+
5
6
- 集群监控:负责监控 redis master 和 slave 进程是否正常工作。
6
7
- 消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
7
8
- 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
8
9
- 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
9
10
10
11
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
12
+
11
13
- 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。
12
14
- 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。
13
15
@@ -17,23 +19,28 @@ sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的
17
19
- 对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。
18
20
19
21
哨兵集群必须部署 2 个以上节点,如果哨兵集群仅仅部署了 2 个哨兵实例,quorum = 1。
22
+
20
23
```
21
24
+----+ +----+
22
25
| M1 |---------| R1 |
23
26
| S1 | | S2 |
24
27
+----+ +----+
25
28
```
29
+
26
30
配置 ` quorum=1 ` ,如果 master 宕机, s1 和 s2 中只要有 1 个哨兵认为 master 宕机了,就可以进行切换,同时 s1 和 s2 会选举出一个哨兵来执行故障转移。但是同时这个时候,需要 majority,也就是大多数哨兵都是运行的。
31
+
27
32
```
28
33
2 个哨兵,majority=2
29
34
3 个哨兵,majority=2
30
35
4 个哨兵,majority=2
31
36
5 个哨兵,majority=3
32
37
...
33
38
```
39
+
34
40
如果此时仅仅是 M1 进程宕机了,哨兵 s1 正常运行,那么故障转移是 OK 的。但是如果是整个 M1 和 S1 运行的机器宕机了,那么哨兵只有 1 个,此时就没有 majority 来允许执行故障转移,虽然另外一台机器上还有一个 R1,但是故障转移不会执行。
35
41
36
42
经典的 3 节点哨兵集群是这样的:
43
+
37
44
```
38
45
+----+
39
46
| M1 |
@@ -51,51 +58,58 @@ sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的
51
58
## redis 哨兵主备切换的数据丢失问题
52
59
### 两种情况和导致数据丢失
53
60
主备切换的过程,可能会导致数据丢失:
61
+
54
62
- 异步复制导致的数据丢失
63
+
55
64
因为 master->slave 的复制是异步的,所以可能有部分数据还没复制到 slave,master 就宕机了,此时这部分数据就丢失了。
56
65
57
66
![ async-replication-data-lose-case] ( /images/async-replication-data-lose-case.png )
58
67
59
68
- 脑裂导致的数据丢失
69
+
60
70
脑裂,也就是说,某个 master 所在机器突然** 脱离了正常的网络** ,跟其他 slave 机器不能连接,但是实际上 master 还运行着。此时哨兵可能就会** 认为** master 宕机了,然后开启选举,将其他 slave 切换成了 master。这个时候,集群里就会有两个 master ,也就是所谓的** 脑裂** 。
61
71
62
- 此时虽然某个 slave 被切换成了master ,但是可能 client 还没来得及切换到新的 master,还继续向旧 master 写数据。因此旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会清空,重新从新的 master 复制数据。而新的 master 并没有后来 client 写入的数据,因此,这部分数据也就丢失了。
72
+ 此时虽然某个 slave 被切换成了 master ,但是可能 client 还没来得及切换到新的 master,还继续向旧 master 写数据。因此旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会清空,重新从新的 master 复制数据。而新的 master 并没有后来 client 写入的数据,因此,这部分数据也就丢失了。
63
73
64
74
![ redis-cluster-split-brain] ( /images/redis-cluster-split-brain.png )
65
75
66
76
### 数据丢失问题的解决方案
67
77
进行如下配置:
78
+
68
79
``` bash
69
80
min-slaves-to-write 1
70
81
min-slaves-max-lag 10
71
82
```
83
+
72
84
表示,要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒。
73
85
74
86
如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了。
75
87
76
88
- 减少异步复制数据的丢失
89
+
77
90
有了 ` min-slaves-max-lag ` 这个配置,就可以确保说,一旦 slave 复制数据和 ack 延时太长,就认为可能 master 宕机后损失的数据太多了,那么就拒绝写请求,这样可以把 master 宕机时由于部分数据未同步到 slave 导致的数据丢失降低的可控范围内。
78
91
79
92
- 减少脑裂的数据丢失
93
+
80
94
如果一个 master 出现了脑裂,跟其他 slave 丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的 slave 发送数据,而且 slave 超过 10 秒没有给自己 ack 消息,那么就直接拒绝客户端的写请求。因此在脑裂场景下,最多就丢失 10 秒的数据。
81
95
82
96
## sdown 和 odown 转换机制
83
97
- sdown 是主观宕机,就一个哨兵如果自己觉得一个 master 宕机了,那么就是主观宕机
84
98
- odown 是客观宕机,如果 quorum 数量的哨兵都觉得一个 master 宕机了,那么就是客观宕机
85
99
86
- sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过了 ` is-master-down-after-milliseconds ` 指定的毫秒数之后,就主观认为 master 宕机了;如果一个哨兵在指定时间内,收到了 quorum 数量的 其它哨兵也认为那个 master 是 sdown 的,那么就认为是 odown 了。
100
+ sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过了 ` is-master-down-after-milliseconds ` 指定的毫秒数之后,就主观认为 master 宕机了;如果一个哨兵在指定时间内,收到了 quorum 数量的其它哨兵也认为那个 master 是 sdown 的,那么就认为是 odown 了。
87
101
88
102
## 哨兵集群的自动发现机制
89
- 哨兵互相之间的发现,是通过 redis 的 pub/sub 系统实现的,每个哨兵都会往` __sentinel__:hello ` 这个 channel 里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。
103
+ 哨兵互相之间的发现,是通过 redis 的 ` pub/sub ` 系统实现的,每个哨兵都会往` __sentinel__:hello ` 这个 channel 里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。
90
104
91
- 每隔两秒钟,每个哨兵都会往自己监控的某个 master+slaves 对应的` __sentinel__:hello ` channel 里** 发送一个消息** ,内容是自己的 host、ip 和 runid 还有对这个 master 的监控配置。
105
+ 每隔两秒钟,每个哨兵都会往自己监控的某个 master+slaves 对应的` __sentinel__:hello ` channel 里** 发送一个消息** ,内容是自己的 host、ip 和 runid 还有对这个 master 的监控配置。
92
106
93
- 每个哨兵也会去** 监听** 自己监控的每个 master+slaves 对应的` __sentinel__:hello ` channel,然后去感知到同样在监听这个 master+slaves 的其他哨兵的存在。
107
+ 每个哨兵也会去** 监听** 自己监控的每个 master+slaves 对应的` __sentinel__:hello ` channel,然后去感知到同样在监听这个 master+slaves 的其他哨兵的存在。
94
108
95
109
每个哨兵还会跟其他哨兵交换对 ` master ` 的监控配置,互相进行监控配置的同步。
96
110
97
111
## slave 配置的自动纠正
98
- 哨兵会负责自动纠正 slave 的一些配置,比如 slave 如果要成为潜在的 master 候选人,哨兵会确保 slave 复制现有 master 的数据; 如果 slave 连接到了一个错误的 master 上,比如故障转移之后,那么哨兵会确保它们连接到正确的 master 上。
112
+ 哨兵会负责自动纠正 slave 的一些配置,比如 slave 如果要成为潜在的 master 候选人,哨兵会确保 slave 复制现有 master 的数据; 如果 slave 连接到了一个错误的 master 上,比如故障转移之后,那么哨兵会确保它们连接到正确的 master 上。
99
113
100
114
## slave->master 选举算法
101
115
如果一个 master 被认为 odown 了,而且 majority 数量的哨兵都允许主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个 slave 来,会考虑 slave 的一些信息:
@@ -105,20 +119,22 @@ sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过
105
119
- 复制 offset
106
120
- run id
107
121
108
- 如果一个 slave 跟 master 断开连接的时间已经超过了` down-after-milliseconds ` 的 10 倍,外加 master 宕机的时长,那么 slave 就被认为不适合选举为 master。
122
+ 如果一个 slave 跟 master 断开连接的时间已经超过了 ` down-after-milliseconds ` 的 10 倍,外加 master 宕机的时长,那么 slave 就被认为不适合选举为 master。
123
+
109
124
```
110
125
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
111
126
```
112
127
113
128
接下来会对 slave 进行排序:
129
+
114
130
- 按照 slave 优先级进行排序,slave priority 越低,优先级就越高。
115
131
- 如果 slave priority 相同,那么看 replica offset,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高。
116
132
- 如果上面两个条件都相同,那么选择一个 run id 比较小的那个 slave。
117
133
118
134
## quorum 和 majority
119
- 每次一个哨兵要做主备切换,首先需要 quorum 数量的哨兵认为 odown,然后选举出一个哨兵来做切换,这个哨兵还得得到 majority 哨兵的授权,才能正式执行切换。
135
+ 每次一个哨兵要做主备切换,首先需要 quorum 数量的哨兵认为 odown,然后选举出一个哨兵来做切换,这个哨兵还需要得到 majority 哨兵的授权,才能正式执行切换。
120
136
121
- 如果 quorum < majority,比如 5 个哨兵,majority 就是 3,quorum 设置为2 ,那么就 3 个哨兵授权就可以执行切换。
137
+ 如果 quorum < majority,比如 5 个哨兵,majority 就是 3,quorum 设置为 2 ,那么就 3 个哨兵授权就可以执行切换。
122
138
123
139
但是如果 quorum >= majority,那么必须 quorum 数量的哨兵都授权,比如 5 个哨兵,quorum 是 5,那么必须 5 个哨兵都同意授权,才能执行切换。
124
140
@@ -130,6 +146,6 @@ sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过
130
146
如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待 failover-timeout 时间,然后接替继续执行切换,此时会重新获取一个新的 configuration epoch,作为新的 version 号。
131
147
132
148
## configuration 传播
133
- 哨兵完成切换之后,会在自己本地更新生成最新的 master 配置,然后同步给其他的哨兵,就是通过之前说的 pub/sub 消息机制。
149
+ 哨兵完成切换之后,会在自己本地更新生成最新的 master 配置,然后同步给其他的哨兵,就是通过之前说的 ` pub/sub ` 消息机制。
134
150
135
- 这里之前的 version 号就很重要了,因为各种消息都是通过一个 channel 去发布和监听的,所以一个哨兵完成一次新的切换之后,新的 master 配置是跟着新的 version 号的。其他的哨兵都是根据版本号的大小来更新自己的 master 配置的。
151
+ 这里之前的 version 号就很重要了,因为各种消息都是通过一个 channel 去发布和监听的,所以一个哨兵完成一次新的切换之后,新的 master 配置是跟着新的 version 号的。其他的哨兵都是根据版本号的大小来更新自己的 master 配置的。
0 commit comments