Redis 高可用
问题
如何保证 Redis 的高可用?从部署架构、数据持久化、故障转移等维度如何设计?
答案
高可用方案全景
持久化保障
参见 Redis 持久化,生产环境推荐混合持久化(RDB + AOF),确保数据不丢失。
主从 + 哨兵
参见 Redis 集群方案,哨兵模式实现自动故障转移。
关键配置建议:
生产环境推荐配置
# 哨兵个数 ≥ 3(奇数),部署在不同机器
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
# 从节点配置
replica-read-only yes # 从节点只读
replica-serve-stale-data yes # 主节点下线时从节点仍可读
min-replicas-to-write 1 # 至少 1 个从节点同步成功才允许写
min-replicas-max-lag 10 # 从节点最大延迟 10 秒
Redis Cluster
适合大规模部署,自带分片和高可用。参见 Redis 集群方案。
客户端最佳实践
连接池配置
Jedis 连接池推荐配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(200); // 最大连接数
config.setMaxIdle(50); // 最大空闲连接
config.setMinIdle(10); // 最小空闲连接
config.setMaxWaitMillis(3000); // 获取连接最大等待时间
config.setTestOnBorrow(true); // 借用时检测连接有效性
config.setTestWhileIdle(true); // 空闲时检测
降级策略
Redis 不可用时的降级
public Object getData(String key) {
try {
Object value = redis.get(key);
if (value != null) return value;
} catch (Exception e) {
log.warn("Redis 不可用,走降级逻辑", e);
// 降级方案:
// 1. 本地缓存(Caffeine)
// 2. 直接查数据库(限流保护)
// 3. 返回默认值
}
return getFromDBWithRateLimit(key);
}
大 Key 问题
大 Key 会导致内存不均、网络阻塞、主从同步延迟等问题。
| 类型 | 大 Key 标准 |
|---|---|
| String | value 超过 10KB |
| Hash/List/Set/ZSet | 元素超过 5000 个 |
发现大 Key
# Redis 4.0+ 内置大 Key 扫描
redis-cli --bigkeys
# 更精确的内存分析
redis-cli --memkeys
删除大 Key(避免阻塞)
# Redis 4.0+ 异步删除
UNLINK bigkey
# 渐进式删除 Hash
HSCAN bigkey cursor COUNT 100
# 然后逐批 HDEL
监控告警
| 指标 | 阈值建议 | 命令 |
|---|---|---|
| 内存使用率 | < 80% | INFO memory |
| 连接数 | < maxclients 的 80% | INFO clients |
| 命中率 | > 95% | INFO stats(keyspace_hits / (hits + misses)) |
| 慢查询 | 关注 | SLOWLOG GET 10 |
| 主从延迟 | < 1 秒 | INFO replication(master_repl_offset 差值) |
常见面试问题
Q1: Redis 如何保证高可用?
答案:
四个层面:
- 持久化:混合持久化(RDB + AOF)保证数据不丢失
- 多副本:主从复制提供数据冗余
- 自动故障转移:Sentinel(中小规模)或 Cluster(大规模)自动检测故障并切换
- 客户端兜底:连接池、重试机制、降级策略、多级缓存
Q2: 如何处理大 Key?
答案:
- 发现:
redis-cli --bigkeys扫描,或通过监控SLOWLOG发现处理慢的 key - 拆分:将大 Hash 按前缀拆成多个小 Hash,将大 List 按时间或 ID 范围分片
- 删除:使用
UNLINK(异步删除)代替DEL,或渐进式删除(HSCAN + HDEL) - 预防:设计时控制集合类型元素数量,String value 不超过 10KB
Q3: Redis 为什么这么快?
答案:
- 内存操作:数据存储在内存中,读写速度远高于磁盘
- 单线程模型:避免了多线程上下文切换和锁竞争的开销
- I/O 多路复用:使用 epoll/kqueue 处理大量并发连接
- 高效数据结构:SDS、ziplist/listpack、skiplist 等针对性能优化的数据结构
- 单线程避免锁:核心操作串行执行,不需要加锁
Redis 6.0 的多线程
Redis 6.0 引入了 I/O 多线程(io-threads),但只用于网络读写(解析请求、发送响应),命令执行仍然是单线程。这既利用了多核 CPU 的网络处理能力,又保持了单线程执行的简单性和安全性。