Redis Sentinel
概述
在不使用 cluster 情况下,Redis 哨兵机制提供了 Redis 的高可用架构。哨兵提供了以下特性:
- Redis 实例监控;
- 故障通知,当 Redis 实例发生故障,哨兵可以通过 api 通知系统管理员或监控程序;
- 自动故障转移,当 master 不幸挂掉的时候,哨兵可以自动启动故障转移,将某个副本提升为新的 master,其他副本则被配置使用该新的 master,使用 Redis 的应用在连接的时候也会被通知使用的新的地址;
- 配置提供者,客户端连接哨兵询问某个服务的 master 的地址,如果发生了故障转移,哨兵会报告新的地址;
注1:Sentinel 和 “哨兵”是一个意思,以下会混用。
注2:以下文档中有时会用“挂了”这个词代替 down,但是“挂了”这个词不够准确,“挂了”给人的感觉是服务进程停止了,但是实际上有可能是发生了网络分区,实例并没有挂,只是无法访问。
运行 sentinel
#以下两种运行方式相同,不论哪种方式都必须提供 sentinel 配置文件,配置文件用来提供初始配置,同时用于保存当前状态,例如生故障转移之后,新的 master 会被写入配置文件。
redis-sentinel /path/to/sentinel.conf
redis-server /path/to/sentinel.conf --sentinel
Sentinels 默认使用 26379 tcp 端口监听连接,因此 26379 端口必须开放以便接受来自其他 Sentinel 实例的连接,否则 Sentinel 实例无法通信,意味着无法达成一致,从而无法执行故障转移。
部署 sentinel 须知
- 应该至少有三个 sentinel 实例才能保证可靠性;
- 三个 sentinel 实例应该是分布在不同的机器或者虚拟机上,应该确保他们不会同时挂掉,如果都部署在一台机器上,这台机器挂了,那么整个集群显然就挂了。
- sentinel+Redis 分布式系统不能保证在故障转移过程中的已确认的写不会丢失,因为 Redis 使用异步复制。可以想象下有两种情况会丢失数据,情况1:master 突然挂掉,写入的 master 的东西还没来得及同步到副本;情况2:master 和某个客户端(C)被分区了,但是 C 在故障转移过程中依然可以向该 master 写入数据,但是故障转移结束后,当分区恢复,master 会被 sentinel 配置为副本,并从新的 master 同步数据,因此 C 写入的数据会丢失。
- 客户端需要对 sentinel 提供支持,大部分流行的客户端都支持 sentinel,但并不是所有客户端;
- 高可用部署必须要在实际环境中进行测试,不测试,很可能无法正常工作,等到故障发生时,一切都已经晚了;
在第二种分区的情况下,我们可以采用以下配置,来减少数据丢失:
为什么是减少而不是杜绝?因为在 min-replicas-max-lag 时间范围内,分区中的 master 依然接受写入。
# 配置 master 至少有多少个副本能够写才接收写入
min-replicas-to-write 1
# 配置 master 在 min-replicas-to-write 条件不满足达到多长时间停止接收写入
min-replicas-max-lag 10
因为副本是异步复制,因此副本不可写入的实际含义是:副本和 master 断开连接或者副本没有向 master 发送异步确认(asynchronous acknowledges)。
配置 sentinel
sentinel 支持同时监控多组 Redis 实例,每组实例都包含一个 master 和 若干个副本。配置的时候我们只要指定 master 就可完成对组的监控。以下是典型配置:
# 监控一个组,给组取名 mymaster,组中的 master 节点的 ip 和端口分别是 127.0.0.1 和 6379,最后一个数字 2 表示法定人数。
# 这里的 2 表示当有 2 个 sentinel 都认为该 master 挂了,那么可客观认为该 master 确实挂了,并在半数以上 sentinel 投票授权许可的情况下,才真正开始故障转移。
# 可见法定人数只是用于检测 master 是否正常,数值越小,检测越灵敏,真正开启故障转移还需要得到半数以上的 sentinel 投票许可。
sentinel monitor mymaster 127.0.0.1 6379 2
# 配置多长时间内 Redis 实例不响应 ping 或者回应了错误(replying with error),sentinel 才认为实例挂了(DOWN)。
sentinel down-after-milliseconds mymaster 60000
# 这个配置是防止多个 sentinel 同时对一个 master 执行故障转移,一个 sentinel 执行后,其他的必须等 2 * failover-timeout 后才能开始。
sentinel failover-timeout mymaster 180000
# 配置多少个副本在故障转移的同时可被重新配置使用新 master,数值越大,故障转移所需时间越短。 但有时候你可能希望在故障转移过程中,副本仍然可以提供旧数据服务,那么可以将该数值配小点。
sentinel parallel-syncs mymaster 1
一个简单的配置拓扑如下,其中 M 表示 master,R 表示副本, S 表示 sentinel 实例,字母后面的数字用于区分不同的实例。 每个方框代表一台机器,quorum 是法定人数。
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2
sentinel、docker 和 NAT
sentinel 依赖 pub/sub 机制自动发现其他 sentinel 实例,如果使用 docker 端口转发,那么 sentinel 收到的其他 sentinel 发布的端口和 ip 可能是不正确的。此时我们明确配置各个 sentinel 的实际 ip 和端口。
sentinel announce-ip <ip>
sentinel announce-port <port>
主机名称
从 redis 6.2 之后,开始支持使用主机名称配置 sentinel,默认不开启,具体配置方式参考这里。
连 sentinel 查信息
可以连接 sentinel 查 master/replica/sentinel 的信息,可以借助于 redis-cli
连接 sentinel。
$ redis-cli -p 5000
127.0.0.1:5000> sentinel master mymaster
127.0.0.1:5000> SENTINEL replicas mymaster
127.0.0.1:5000> SENTINEL sentinels mymaster
获取当前 master
127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"
测试故障转移
redis-cli -p 6379 DEBUG sleep 30
可以借助 debug 命令让 master 睡 30s, sentinel 应该会检测到 master 不可用,从而开启故障转移。
Sentinel api
sentinel 提供了 api 来检测其状态,检查 master 和副本的健康状况,运行期间修改 Redis 配置,还可以选择订阅 sentinel 发布的事件。我们可以使用 redis-cli
连接 sentinel 和 sentinel 通信。sentinel 使用的是 redis 协议,因此可以使用 redis-cli
和 sentinel 通信。 api 一大堆,具体可以参考这里。
运行时重新配置 Sentinel
例如,运行期间动态调整 down-after-milliseconds 和 quorum:
SENTINEL SET mymaster down-after-milliseconds 1000
SENTINEL SET mymaster quorum 5
需要注意的是,每个监听 my-master 的 sentinel 实例都需要执行同样的命令,一个 sentinel 上执行的修改操作是不会分发到其他 sentinel 实例的。
添加删除 Sentinel
动态添加 sentinel 实例是很简单的,因为 sentinel 会自动发现其他 sentinel 实例,添加多个时候,建议一个一个的加(建议间隔 30s),让前一个添加的实例被感知之后再添加新的实例。删除 sentinel 不会自动生效,需要执行以下命令:
# 执行下面两条中的其中一条即可
SENTINEL RESET *
SENTINEL RESET mymaster
# 最后我们可以利用下面的命令检查当前监控 master 的 sentinel 实例信息
SENTINEL MASTER mymaster
SDOWN and ODOWN 失败状态
sentinel 有两个 down 的概念,分别是 sdown(subjective down)和 odown(objective down)。sdown 是一个 sentinel 内部的状态,即当前 sentinel 主观认为 Redis 实例 down 了,啰嗦下为什么说是主观呢?因为只有自己这么认为是不够客观的,当达到 quorum 个 sentinel 实例都是认为 sdown,相当于大家达成一致,此时进入 odown 状态,即可客观认为 master down 了。 odown 状态仅适用于 master,不适用于副本。
一个进入 sdown 状态的 sentinel 可以通过 SENTINEL is-master-down-by-addr
命令获取其他 sentinel 的反馈。sentinel 发出的 Ping,如果在一定时间内(由down-after-milliseconds配置)没有有效响应,则进入 sdown 状态。有效的响应包括:
- PING replied with +PONG.
- PING replied with -LOADING error.
- PING replied with -MASTERDOWN error.
Sentinel 自动发现
每个 sentinel 实例都监听它所监控的 master 及副本中名为 sentinel:hello 的 channel 以感知其他 sentinel 实例,同时向该 channel 发布(通过 hello 消息)自身的 ip、端口和 runid。这样监控同一个 master 的 sentinel 可以相互感知。
温馨提示:反馈需要登录