redis-sentinel-pool
简体中文 | English
基于 redis 1.2.1 的 sentinel 模块和 bb8 连接池,构建的 Sentinel 感知的异步 Redis 连接池。
设计目标:
- 对业务完全透明的 master failover:哨兵切换主节点后,业务侧 无需 修改任何地址或重启进程,下一次
pool.get()就会拿到指向新 master 的连接。 - 秒级感知:可选的后台 watcher 直接订阅 Sentinel 的
+switch-masterPub/Sub 事件,收到通知后 立即 作废全池连接。 - 零侵入接口:借出的就是
redis::aio::MultiplexedConnection,所有redis::AsyncCommands/redis::cmd!都可正常使用。 - 可选的自动重试:
SentinelPool::execute(|conn| async { ... })在底层错误属于"连接级 / 短暂错误"时自动换连接重试,调用方写起来跟操作单机 Redis 一样。
添加依赖
[]
= { = "../redis-sentinel-rs" } # 或发布到 crates.io 后的版本号
= { = "1", = ["full"] }
= { = "1.2.1", = ["aio", "tokio-comp"] }
本 crate 自身已经
pub use redis;,所以也可以直接通过redis_sentinel_pool::redis::AsyncCommands访问。
最小示例
use AsyncCommands;
use ;
async
让 failover 完全透明
let result: = pool
.execute
.await?;
execute 内部会:
pool.get().await拿一条连接;- 执行闭包;
- 若失败且属于 可重试 错误(IO 错误、
RetryMethod::Reconnect/WaitAndRetry/RetryImmediately等),主动调用force_refresh()让全池连接作废,然后sleep(backoff * attempt)重试; - 重试次数耗尽后返回 [
SentinelPoolError::RetryExhausted]。
工作原理
┌─────────────────┐ +switch-master ┌─────────────────┐
│ 业务代码 │ ◀──────────────────────────── │ Sentinel 集群 │
│ pool.get() │ │ (26379/26380/...)│
│ pool.execute() │ └────────┬────────┘
└────────┬────────┘ │
│ borrow │ subscribe
▼ ▼
┌─────────────────┐ bump_epoch on failover ┌──────────────────────┐
│ bb8::Pool │ ◀──────────────────────│ Watcher (后台 task) │
│ + Manager │ └──────────────────────┘
└────────┬────────┘
│ async_get_connection() ───► 每次都向 sentinel 询问当前 master
▼
┌─────────────────┐
│ master 节点 │
└─────────────────┘
- Manager 实现了
bb8::ManageConnection:connect():通过共享的SentinelClient::async_get_connection()创建一条到当前 master 的MultiplexedConnection,并打上当前epoch。is_valid():每次借出做PING,必要时再发一条ROLE校验真的是 master(避免连到刚被 demote 的旧主)。has_broken():连接出生的 epoch 落后于全局 epoch,立刻视为坏连接。
- Watcher 后台 task:订阅 Sentinel 的
+switch-master频道,收到与本服务相关的事件就bump_epoch(),让池里所有旧连接秒级失效;watcher 与池本身是 解耦 的,关闭它(enable_watcher(false))后池仍然能在第一次失败时回收旧连接、自动指向新 master,只是恢复速度会略慢。
配置项一览
| 方法 | 默认值 | 说明 |
|---|---|---|
max_size |
16 |
池最大连接数 |
min_idle |
None |
预热的最小空闲连接数 |
connection_timeout |
5s |
借连接的等待超时 |
idle_timeout |
600s |
空闲连接最长存活 |
max_lifetime |
1800s |
单条连接最大生命周期 |
verify_role_on_checkout |
true |
借出时额外发送 ROLE 校验当前节点仍是 master |
max_retries |
3 |
execute 系列的最大尝试次数 |
retry_backoff |
100ms |
重试退避的基线,每次重试乘以重试序号 |
enable_watcher |
true |
是否启用后台 +switch-master watcher |
watcher_reconnect_backoff |
2s |
watcher 断开后的重连退避 |
redis_db / username / password |
None |
目标 Redis 节点的鉴权信息 |
redis_protocol |
RESP2 |
Redis 协议版本 |
redis_tls_mode |
None |
与 Redis 节点之间是否使用 TLS(需启用 tls feature) |
运行示例
仓库自带一份 3 节点 Sentinel 的 docker compose,可以一键拉起本地环境
(无需改 hosts、跨平台、宿主机直接 127.0.0.1 可达):
详见 docker/README.md。
仓库自带 3 个 Rust 示例:
# 最简使用
RUST_LOG=info
# failover 演练:在循环里持续 set/get,期间手动触发 sentinel failover
RUST_LOG=info,redis_sentinel_pool=debug
# 另一个终端:
# 实时观察 watcher 和 epoch
RUST_LOG=info,redis_sentinel_pool=debug
TLS 支持
启用 tls feature 后即可使用 TLS:
= { = "0.1", = ["tls"] }
let cfg = new
.redis_tls_mode;
License
双协议:MIT OR Apache-2.0。