Redis哨兵

Sentinel是Redis的高可用性(high availability)解决方案

由一个或多个 Sentinel 实例(instance)组成的 Sentinel 系统(system)可以监视任意多个主服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

实际上这意味着使用哨兵模式,可以创建一个不用人为干预而应对各种故障的Redis部署。

哨兵模式的功能列表

  • 监听:哨兵不断的检查 master 和 slave 是否正常的运行。

  • 通知:当监控的某台 Redis 实例发生问题时,可以通过API通知系统管理员和其他的应用程序。

  • 自动故障转移:如果一个 master 不正常运行了,哨兵可以启动一个故障转移进程,将一个 slave 升级成为 master,其他的 slave 被重新配置使用新的 master,并且应用程序使用 Redis 服务端通知的新地址。

  • 配置提供者:哨兵作为 Redis 客户端发现的权威来源:客户端连接到哨兵请求当前可靠的 master 的地址。如果发生故障,哨兵将报告新地址。

启动并初始化Sentinel

1
2
3
$ redis-sentinel /path/to/your/sentinel.conf
或者
$ redis-server /path/to/your/sentinel.conf --sentinel

当一个Sentinel启动时,它需要执行以下五个步骤:

  • 初始化服务器
  • 将普通的Redis服务器使用的代码替换成Sentinel专用代码
  • 初始化Sentinel状态
  • 根据给定的配置文件,初始化Sentinel监视的主服务器列表
  • 创建连接主服务器的网络连接

Redis的master和slave主从设定可以通过slaveof命令操作,举个🌰:

1
2
3
4
redis-cli -p 6380
127.0.0.1:6380> ping
PONG
127.0.0.1:6380> slaveof 127.0.0.1 6379

通过Mac的HomeBrew安装Redis的话,默认配置文件在/usr/local/etc/redis-sentinel.conf目录
复制出两份相同文件,修改port端口号,简单的配置如下

1
2
3
4
5
6
7
port 26379
# monitor后面的mymsater标志master和它的slave,最后一个参数2表示quoram设置
sentinel monitor mymaster 127.0.0.1 6379 2
# 在这个时间范围内不能接收响应,master将会被标记为故障
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

默认运行在26379端口号,本地服务开多个哨兵的话,将26379改成26380、26381尝试。

启动日志如下:

1
2
2285:X 24 Mar 23:34:17.514 # Sentinel ID is 0440e012ba17a7a5b4b517cab3589e764bbc03e3
2285:X 24 Mar 23:34:17.514 # +monitor master mymaster 127.0.0.1 6379 quorum 2

如果启动三个Sentinel后,你就能从日志中看到已经成功启动了三个Sentinel,并且都是监听同一个Master服务器:

1
2
3
2409:X 24 Mar 23:40:27.673 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2409:X 24 Mar 23:40:27.905 * +sentinel sentinel 1c60d45db8d9f17f0be5a0ccc2dc62fb57de2d4b 127.0.0.1 26380 @ mymaster 127.0.0.1 6379
2409:X 24 Mar 23:40:29.123 * +sentinel sentinel 0440e012ba17a7a5b4b517cab3589e764bbc03e3 127.0.0.1 26379 @ mymaster 127.0.0.1 6379


Sentinel的API

通过redis-cli -p 26379登录Sentinel(因为Sentinel就是一个特殊的Redis服务器)

检查master是否正常监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
redis-cli -p 26379
127.0.0.1:26379> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
7) "runid"
8) "737b3c33842f4c251b65494b4bf356ce2af8ad8c"
# flags 是 master。如果master down了,我们在这里希望看到 s_down 或者 o_down。
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "466"
19) "last-ping-reply"
20) "466"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "6396"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "1492980"
29) "config-epoch"
30) "0"
# 表示该Master下有一个slave(例如:我刚才在6380端口启动的)
31) "num-slaves"
32) "1"
# 表示Sentinel已经检测到这个Master另外两个Sentinel
33) "num-other-sentinels"
34) "2"
# 集群配置
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"

获取当前master地址

1
2
3
127.0.0.1:26379> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"

故障转移测试

关掉Master服务器

1
$ redis-cli -p 6379 shundown

Sentinel哨兵的打印日志:

1
2
2379:X 25 Mar 00:27:52.341 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
2379:X 25 Mar 00:27:52.341 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380

重新启动6379的Redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ redis-server --port 6379
2604:M 25 Mar 00:29:38.000 # Server initialized
2604:M 25 Mar 00:29:38.000 * DB loaded from disk: 0.000 seconds
2604:M 25 Mar 00:29:38.000 * Ready to accept connections
2604:S 25 Mar 00:29:48.168 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
2604:S 25 Mar 00:29:48.168 * SLAVE OF 127.0.0.1:6380 enabled (user request from 'id=2 addr=127.0.0.1:58752 fd=8 name=sentinel-fe82d064-cmd age=10 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=r cmd=exec')
2604:S 25 Mar 00:29:48.371 * Connecting to MASTER 127.0.0.1:6380
2604:S 25 Mar 00:29:48.371 * MASTER <-> SLAVE sync started
2604:S 25 Mar 00:29:48.371 * Non blocking connect for SYNC fired the event.
2604:S 25 Mar 00:29:48.371 * Master replied to PING, replication can continue...
2604:S 25 Mar 00:29:48.372 * Trying a partial resynchronization (request 14da919a7f784c20260fe79893734941b6098734:1).
2604:S 25 Mar 00:29:48.373 * Full resync from master: d2b5bdafe3c3fd8c7f8e0dfe7e0159e33c9a40fb:608136
2604:S 25 Mar 00:29:48.373 * Discarding previously cached master state.
2604:S 25 Mar 00:29:48.464 * MASTER <-> SLAVE sync: receiving 190 bytes from master
2604:S 25 Mar 00:29:48.464 * MASTER <-> SLAVE sync: Flushing old data
2604:S 25 Mar 00:29:48.464 * MASTER <-> SLAVE sync: Loading DB in memory
2604:S 25 Mar 00:29:48.465 * MASTER <-> SLAVE sync: Finished with success

从上面可以看出,6379 服务器挂掉后,哨兵可以启动一个故障转移进程,将一个 slave(例如:6380)升级成为master。接着 6379 启动后,哨兵系统会将 6379 设定为 master(6380)的 slave,开始复制 maste r的数据。

通过测试,发现当主服务器出现故障的时候,会自动让从服务器成为主服务器,继续正常的工作,如果挂掉的主服务器重新启动的话,会让它成为新任主服务器的slave,完成故障转移。

还有很多API就不列举了,详细可看第一个参考资料。


小结:

这把学习记录了哨兵系统的简单介绍,还有如何使用,以及它是如何完成故障转移的详细过程,感觉还是好多坑没填🐶


参考资料
[1]Redis哨兵-实现Redis高可用—Redis中文网
[2]Redis设计与实现第二版—黄健宏