← 中文资源

简体中文版本

Redis Sentinel 故障转移客户端

通过 Redis Sentinel 接入实现自动故障转移:读请求走副本、副本故障回退主库、写失败等待切换后重解析主节点地址。

阅读英文原文

示例说明

主从 Redis 的客户端必须理解拓扑会变:主库宕机后哨兵把某个副本提升为新主,客户端要能拿到新地址。master_for 与 slave_for 每次都向哨兵查询当前角色,连接串不再写死。读写分离之外,两条容错路径很关键——副本读失败回退主库保可用性,写失败等待切换窗口后重新解析地址重试。

技术要点

  • 角色解析实时询问哨兵集群
  • 读副本失败自动回退主库
  • 写失败重解析地址越过切换窗口

代码解读

三台哨兵防脑裂,socket_timeout 压短探测延迟;cache_get 先打副本读,连接类异常时降级主库;cache_set 捕获连接错误后小睡 200 毫秒让哨兵完成推举,再重新 master_for 拿新主地址重试写入。current_topology 展示运行期动态发现的拓扑结构。

使用建议

切换窗口内的写入仍可能失败,重要数据要有最终一致性兜底。副本读注意复制延迟对一致性的影响。哨兵与 Redis 节点跨可用区部署。

代码示例

import redis
import time

from redis.sentinel import Sentinel

sentinel = Sentinel(
    [('10.0.0.11', 26379), ('10.0.0.12', 26379), ('10.0.0.13', 26379)],
    socket_timeout=0.5,
)

master = sentinel.master_for('mymaster', socket_timeout=1.0)
replica = sentinel.slave_for('mymaster', socket_timeout=1.0)


def cache_get(key: str) -> str | None:
    try:
        return replica.get(key)  # 读走副本,减轻主库压力
    except (redis.ConnectionError, redis.TimeoutError):
        return master.get(key)  # 副本不可用时回退主库


def cache_set(key: str, value: str, ttl: int = 60) -> bool:
    try:
        master.set(key, value, ex=ttl)
        return True
    except redis.ConnectionError:
        # 哨兵可能正在切换,稍等后重新解析主节点地址
        time.sleep(0.2)
        fresh = sentinel.master_for('mymaster', socket_timeout=1.0)
        fresh.set(key, value, ex=ttl)
        return True


def current_topology() -> dict:
    master_addr = sentinel.discover_master('mymaster')
    replicas = sentinel.discover_slaves('mymaster')
    return {
        'master': f'{master_addr[0]}:{master_addr[1]}',
        'replicas': [f'{h}:{p}' for h, p in replicas],
    }



print('topology:', current_topology())
cache_set('session:7', 'active', ttl=300)
print('read back:', cache_get('session:7'))