# Redis 生产配置
`cache-redis` 是可选 feature,默认 workspace 不引入 Redis 依赖。启用后可使用 `RedisCacheStore`、应用级 `RedisShardedCacheStore` 以及 Redis-backed limiter。
## 单节点 cache store
```rust,no_run
use rs_zero::cache_redis::{RedisCacheConfig, RedisCacheStore};
let store = RedisCacheStore::new(RedisCacheConfig {
url: "redis://127.0.0.1:6379".to_string(),
namespace: "orders".to_string(),
breaker: rs_zero::cache_redis::RedisBreakerConfig::go_zero_defaults(),
..RedisCacheConfig::default()
})?;
# Ok::<(), rs_zero::cache_redis::RedisCacheError>(())
```
生产环境必须设置连接超时、命令超时和稳定 namespace。不要把 Redis URL、密码或 cache key 写入指标标签或日志字段。
## Redis breaker
`RedisCacheStore` 可在 adapter 内启用 breaker 保护,覆盖连接获取和命令执行。默认 `RedisBreakerConfig::default()` 保持关闭以兼容既有行为;生产配置建议显式使用 `RedisBreakerConfig::go_zero_defaults()`,或按服务容量设置 `failure_threshold`、`reset_timeout` 和 rolling-window policy。
breaker 打开后,请求不会继续打到底层 Redis client。拒绝结果会进入现有 `RedisUnavailablePolicy`:
- fail-closed:返回包含 circuit breaker 的错误。
- fail-open:`get` 返回 miss,`set` / `delete` / `delete_many` 跳过写入。
`NOSCRIPT` 和 Cluster redirect 这类可恢复结果不计为 breaker 失败;连接错误、timeout 和普通 backend 错误会计为失败。
## Redis Cluster 与应用级分片
rs-zero 明确区分两类能力:
- Redis Cluster:`RedisCacheStore` 在 `cluster.enabled = true` 时使用 `redis-rs` 原生 `ClusterClient`,由成熟客户端处理 16384 slot 路由、`MOVED` / `ASK`、拓扑刷新和重试。
- 应用级分片:`RedisShardedCacheStore` 使用 rendezvous hashing 在多个单节点 Redis 间选 shard,不是 Redis Cluster 协议 adapter。
Cluster 模式下 `RedisCacheConfig.url` 支持逗号分隔 startup nodes,例如 `redis://127.0.0.1:7000,redis://127.0.0.1:7001`。`RedisClusterRouter`、`RedisClusterSlotMap`、`RedisClusterRedirect` 和 `redis_cluster_slot` 保留为诊断与测试工具,不再承担生产请求路由。
## Lua 脚本缓存
`RedisLuaScript` 会按脚本文本计算 SHA1,优先使用 `EVALSHA`。当 Redis 返回 `NOSCRIPT` 时,会执行 `SCRIPT LOAD` 并重试一次。Redis token bucket 与 fixed-window period limiter 通过该封装保留原有 fail-open / fail-closed 配置。
## Redis 不可用降级
默认 `RedisUnavailablePolicy::fail_closed()` 保持兼容:Redis 连接或命令失败会返回错误。只有显式配置 `RedisUnavailablePolicy::fail_open_for_cache()` 时,cache store 才会:
- `get` 失败返回 cache miss。
- `set` 失败跳过写入。
- `delete` / `delete_many` 失败跳过删除。
所有显式降级都会记录低基数降级事件。降级适合“缓存不可用但数据库仍可承载”的场景;不适合依赖 Redis 保证强一致、配额或互斥的路径。
## 指标
启用 `observability` 后,Redis 相关指标包括:
- `rs_zero_redis_commands_total`
- `rs_zero_redis_command_errors_total`
- `rs_zero_redis_command_duration_seconds`
- `rs_zero_redis_events_total`
- `rs_zero_redis_degradations_total`
标签保持低基数:`command`、`event`、`shard`、`result`、`operation`、`action`。breaker 事件使用 `event="breaker"`,结果包括 `success`、`timeout`、`error`、`breaker_rejected`。指标不得包含 Redis key、Redis URL、密码或用户输入。
## 外部测试
默认 CI 只运行离线测试。手动验证外部 Redis 时可使用:
```bash
RS_ZERO_TEST_REDIS_URL=redis://127.0.0.1:6379 \
cargo test --features cache-redis --test cache_redis_external -- --ignored
```
也可使用脚本同时覆盖单节点 Redis roundtrip 和本地 breaker 故障注入:
```bash
scripts/external-integration.sh redis redis-fault
```
手动验证 Redis Cluster 时设置:
```bash
RS_ZERO_TEST_REDIS_CLUSTER_URL=redis://127.0.0.1:7000,redis://127.0.0.1:7001 \
cargo test --features cache-redis --test cache_redis_external -- --ignored
```
或运行:
```bash
RS_ZERO_TEST_REDIS_CLUSTER_URL=redis://127.0.0.1:7000,redis://127.0.0.1:7001 \
scripts/external-integration.sh redis-cluster
```
`redis-cluster` 目标不会自动创建集群,需要传入已有 Redis Cluster startup nodes;这能避免脚本误修改本机 Redis 配置。