Redis 哨兵(Sentinel)机制是 Redis 官方提供的 高可用解决方案,核心目标是解决主从复制架构中 “主节点(Master)故障后无法自动切换” 的问题,实现故障检测、自动故障转移、配置更新和客户端通知,确保 Redis 服务在主节点宕机时仍能持续可用。
1、哨兵的核心功能
- 监控(Monitoring):持续检查主、从节点是否正常运行。
- 通知(Notification):当被监控的 Redis 实例出现问题时,能通过 API 或其他系统发送通知。
- 自动故障转移(Automatic Failover):当主节点故障时,哨兵会启动故障转移流程,选举出新的主节点,并让其他从节点开始复制它。
- 配置提供者(Configuration Provider):客户端连接哨兵系统来查询当前的主节点地址。故障转移发生后,哨兵会提供新的主节点地址。
2、哨兵的工作原理与流程
- 哨兵集群的建立
哨兵本身也是一个分布式集群。多个哨兵节点通过 Redis 的 Pub/Sub 功能自动发现彼此,并相互通信。它们共同组成一个集群,这是为了:
高可用:防止哨兵自身成为单点故障。
决策公正:对主节点的故障判定基于多数哨兵的共识,避免误判。
- 主观下线 (Subjectively Down, SDOWN)
单个哨兵节点通过定期发送 PING 命令来检测主节点是否存活。如果在一个配置的时长(down-after-milliseconds,如 30 秒)内没有收到有效回复(如 PONG、LOADING、MASTERDOWN),该哨兵就会主观地认为这个主节点“下线”了。
主观下线 只是一个哨兵“个人”的看法,不代表事实。
- 客观下线 (Objectively Down, ODOWN)
当一个哨兵认为主节点主观下线后,它会通过 SENTINEL is-master-down-by-addr 命令询问其他哨兵是否也认为该主节点下线。如果达到法定数量(通常是由配置的 quorum 参数决定,例如至少需要 2 个哨兵同意)的哨兵都报告主节点主观下线,那么该主节点就被标记为客观下线。
客观下线 是哨兵集群的集体决策,意味着故障转移的条件被触发。
- 领导者选举 (Leader Election)
一旦主节点被判定为客观下线,哨兵集群需要选举出一个领导者哨兵来负责执行本次故障转移操作。选举使用了 Raft 算法 的思想,每个发现主节点客观下线的哨兵都会要求其他哨兵选举自己为领导者,第一个获得多数票的哨兵成为领导者。
- 故障转移 (Failover)
由选举出的领导者哨兵来执行以下流程:
- 筛选新主节点:从剩余的从节点中,根据规则(优先级 replica-priority、复制偏移量、runId)选出一个最合适的作为新的主节点。
- 提升新主:向选中的从节点发送 SLAVEOF NO ONE 命令,使其升级为主节点。
- 切换从节点:向其他从节点发送 SLAVEOF 命令,让它们开始复制新的主节点。
- 更新配置:将旧主节点更新为新主节点的从节点(这样当旧主节点恢复后,它会自动成为新主节点的从节点)。
- 通知客户端:通过 Pub/Sub 机制发布新主节点的地址信息。
3、关键配置
哨兵的行为由 sentinel.conf 配置文件控制- port 26379 # 哨兵默认运行在26379端口
- daemonize yes # 以守护进程方式运行
- # sentinel monitor <master-name> <ip> <port> <quorum> 定义要监控的主节点。<quorum>是判断客观下线所需的哨兵同意数。
- sentinel monitor mymaster 10.211.55.52 6379 2
- # sentinel down-after-milliseconds <master-name> <ms> 指定多少毫秒无响应则判定节点主观下线。
- sentinel down-after-milliseconds mymaster 5000
- # sentinel failover-timeout <master-name> <ms> 故障转移的超时时间。
- sentinel failover-timeout mymaster 60000
- # sentinel parallel-syncs <master-name> <num>故障转移后,同时向新主节点同步数据的从节点数量。
- sentinel parallel-syncs mymaster 1
复制代码 启动哨兵:- redis-server /path/to/your-sentinel.conf --sentinel
复制代码 4、客户端集成
客户端不再直接连接固定的 Redis 主节点,而是连接哨兵系统。- from redis.sentinel import Sentinel
- # 1. 连接到哨兵集群(可以传入多个哨兵节点地址列表)
- sentinel = Sentinel([('sentinel1.example.com', 26379),
- ('sentinel2.example.com', 26379),
- ('sentinel3.example.com', 26379)],
- socket_timeout=0.5)
- # 2. 通过哨兵发现当前主节点地址
- master = sentinel.discover_master('mymaster') # 返回 (ip, port)
- print(master)
- # 3. 获取一个主节点的连接(用于写操作)
- master_conn = sentinel.master_for('mymaster', socket_timeout=0.5, password='your_redis_password')
- master_conn.set('foo', 'bar')
- # 4. 获取一个从节点的连接(用于读操作,实现读写分离)
- slave_conn = sentinel.slave_for('mymaster', socket_timeout=0.5, password='your_redis_password')
- value = slave_conn.get('foo')
- print(value)
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |