Redis Sentinel 高可用集群
Redis 高可用集群
基于 Docker 搭建单机 Redis HA 集群
官网: https://redis.io/topics/sentinel#sentinel-docker-nat-and-possible-issues
Docker 部署注意事项
Sentinel、Docker、NAT 和可能的问题
Docker 使用一种称为端口映射的技术:与程序认为正在使用的端口相比,在 Docker 容器内运行的程序可能会使用不同的端口公开。这对于在同一服务器中同时使用相同端口运行多个容器非常有用。
Docker 不是唯一发生这种情况的软件系统,还有其他网络地址转换设置可以重新映射端口,有时不是端口而是 IP 地址。
重新映射端口和地址会以两种方式与 Sentinel 产生问题:
- Sentinel 对其他 Sentinel 的自动发现不再有效,因为它基于hello消息,其中每个 Sentinel 宣布它们正在侦听连接的端口和 IP 地址。然而 Sentinel 无法理解地址或端口被重新映射,因此它宣布了一个不正确的信息,其他 Sentinel 无法连接。
- 副本以类似的方式列在Redis 主节点的INFO输出中:主节点通过检查 TCP 连接的远程对等方来检测地址,而端口在握手期间由副本自身通告,但是端口可能是错误的原因与第 1 点中暴露的原因相同。
由于 Sentinel 使用 masters INFO输出信息自动检测副本,因此检测到的副本将无法访问,并且 Sentinel 将永远无法对 master 进行故障转移,因为从系统的角度来看没有好的副本,因此目前没有使用 Sentinel 监视一组使用 Docker 部署的主实例和副本实例的方法,除非您指示 Docker 映射端口 1:1。
对于第一个问题,如果您想使用带有转发端口的 Docker 运行一组 Sentinel 实例(或任何其他重新映射端口的 NAT 设置),您可以使用以下两个 Sentinel 配置指令来强制 Sentinel 宣布一个一组特定的 IP 和端口:
sentinel announce-ip <ip>
sentinel announce-port <port>
请注意,Docker 能够在主机网络模式下运行(查看该--net=host
选项以获取更多信息)。这应该不会产生问题,因为在此设置中不会重新映射端口。
IP 地址和 DNS 名称
旧版本的 Sentinel 不支持主机名,并且需要在任何地方指定 IP 地址。从 6.2 版开始,Sentinel可选支持主机名。
默认情况下禁用此功能。如果您要启用 DNS/主机名支持,请注意:
- Redis 和 Sentinel 节点上的名称解析配置必须可靠并且能够快速解析地址。地址解析中的意外延迟可能会对 Sentinel 产生负面影响。
- 您应该在任何地方使用主机名并避免混合主机名和 IP 地址。为此,请分别对所有 Redis 和 Sentinel 实例使用
replica-announce-ip <hostname>
和sentinel announce-ip <hostname>
。
启用resolve-hostnames
全局配置允许 Sentinel 接受主机名:
- 作为
sentinel monitor
命令的一部分 - 作为副本地址,如果副本使用主机名值
replica-announce-ip
Sentinel 将接受主机名作为有效输入并解析它们,但在宣布实例、更新配置文件等时仍会引用 IP 地址。
启用announce-hostnames
全局配置会使 Sentinel 改用主机名。这会影响对客户端的回复、写入配置文件的值、向副本发出的REPLICAOF命令等。
此行为可能与所有可能明确要求 IP 地址的 Sentinel 客户端不兼容。
当客户端使用 TLS 连接到实例并需要名称而不是 IP 地址以执行证书 ASN 匹配时,使用主机名可能很有用。
Redis
docker-compose.yml
version: '3.1'
services:
master:
image: redis
restart: always
container_name: redis-master
ports:
- 6379:6379
command: redis-server --replica-announce-ip 192.168.1.188 --replica-announce-port 6379
slave1:
image: redis
restart: always
container_name: redis-slave-1
ports:
- 6380:6379
command: redis-server --slaveof redis-master 6379 --replica-announce-ip 192.168.1.188 --replica-announce-port 6380
slave2:
image: redis
restart: always
container_name: redis-slave-2
ports:
- 6381:6379
command: redis-server --slaveof redis-master 6379 --replica-announce-ip 192.168.1.188 --replica-announce-port 6381
- --replica-announce-ip:宿主机 ip
- --replica-announce-port:映射到宿主机端口
Redis Sentinel
docker-compose.yml
version: '3.1'
services:
sentinel1:
image: redis
restart: always
container_name: redis-sentinel-1
ports:
- 26379:26379
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- /usr/local/docker/redis/redis-sentinel/sentinel1.conf:/usr/local/etc/redis/sentinel.conf
sentinel2:
image: redis
restart: always
container_name: redis-sentinel-2
ports:
- 26380:26379
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- /usr/local/docker/redis/redis-sentinel/sentinel2.conf:/usr/local/etc/redis/sentinel.conf
sentinel3:
image: redis
restart: always
container_name: redis-sentinel-3
ports:
- 26381:26379
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- /usr/local/docker/redis/redis-sentinel/sentinel3.conf:/usr/local/etc/redis/sentinel.conf
sentinel1.conf
[sentinel2.conf | sentinel3.conf]
port 26379
sentinel announce-ip 192.168.1.188
sentinel announce-port 26379 # [26380 | 26381]
sentinel monitor mymaster 192.168.1.188 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000
sentinel deny-scripts-reconfig yes
- port:实例 IP 与 docker-compose 中的端口对应
- sentinel announce-ip:宿主机 IP
- announce-port:宿主机端口
测试
docker stop redis-master
完整的故障转移过程
redis-sentinel-3 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-1 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +odown master mymaster 192.168.1.188 6379 #quorum 3/2
# 一致认为 master 客观宕机
# 开始新一轮投票,主持人:redis-sentinel-2,说当前第 7 次会议
redis-sentinel-2 | time # +new-epoch 7
# master 尝试故障转移
redis-sentinel-2 | time # +try-failover master mymaster 192.168.1.188 6379
# 进行 master 选举
redis-sentinel-2 | time # +vote-for-leader ea6a334a070713dbbac0fb4c341309bd4e3368ed 7
redis-sentinel-3 | time # +new-epoch 7
redis-sentinel-1 | time # +new-epoch 7
redis-sentinel-3 | time # +vote-for-leader ea6a334a070713dbbac0fb4c341309bd4e3368ed 7
redis-sentinel-1 | time # +vote-for-leader ea6a334a070713dbbac0fb4c341309bd4e3368ed 7
redis-sentinel-1 | time # +odown master mymaster 192.168.1.188 6379 #quorum 2/2
redis-sentinel-2 | time # f6d68cca0812a70f5ff0e33a556d75b8d437cbe9 voted for ea6a334a070713dbbac0fb4c341309bd4e3368ed 7
redis-sentinel-2 | time # 8892c89a6c724875f952c9333abe475d36463b12 voted for ea6a334a070713dbbac0fb4c341309bd4e3368ed 7
redis-sentinel-1 | time # Next failover delay: I will not start a failover before Fri Aug 27 00:05:25 2021
redis-sentinel-2 | time # +elected-leader master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +failover-state-select-slave master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +selected-slave slave 192.168.1.188:6380 192.168.1.188 6380 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time * +failover-state-send-slaveof-noone slave 192.168.1.188:6380 192.168.1.188 6380 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time * +failover-state-wait-promotion slave 192.168.1.188:6380 192.168.1.188 6380 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +promoted-slave slave 192.168.1.188:6380 192.168.1.188 6380 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +failover-state-reconf-slaves master mymaster 192.168.1.188 6379
redis-sentinel-2 | time * +slave-reconf-sent slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6379
redis-sentinel-1 | time # +config-update-from sentinel ea6a334a070713dbbac0fb4c341309bd4e3368ed 192.168.1.188 26380 @ mymaster 192.168.1.188 6379
redis-sentinel-1 | time # +switch-master mymaster 192.168.1.188 6379 192.168.1.188 6380
redis-sentinel-1 | time * +slave slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6380
redis-sentinel-1 | time * +slave slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-3 | time # +config-update-from sentinel ea6a334a070713dbbac0fb4c341309bd4e3368ed 192.168.1.188 26380 @ mymaster 192.168.1.188 6379
redis-sentinel-3 | time # +switch-master mymaster 192.168.1.188 6379 192.168.1.188 6380
redis-sentinel-3 | time * +slave slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6380
redis-sentinel-3 | time * +slave slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-2 | time # -odown master mymaster 192.168.1.188 6379
redis-sentinel-2 | time * +slave-reconf-inprog slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time * +slave-reconf-done slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +failover-end master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +switch-master mymaster 192.168.1.188 6379 192.168.1.188 6380
redis-sentinel-2 | time * +slave slave 192.168.1.188:6381 192.168.1.188 6381 @ mymaster 192.168.1.188 6380
redis-sentinel-2 | time * +slave slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-3 | time # +sdown slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-1 | time # +sdown slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-2 | time # +sdown slave 192.168.1.188:6379 192.168.1.188 6379 @ mymaster 192.168.1.188 6380
redis-sentinel-3 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-1 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +sdown master mymaster 192.168.1.188 6379
redis-sentinel-2 | time # +odown master mymaster 192.168.1.188 6379 #quorum 3/2
首先 sentinel 主观认为 master 宕机,当有 2 个sentinel 都主观认为 master 宕机,那么 master 真的可能宕机了
sentinel-2 (主领导)给出最终方案,+odown