性能优化、可观测性、故障诊断与综合面试
系统梳理 Redis 性能基线、可观测性、故障诊断、容量规划、压测、降级、容灾演练与综合面试回答方法。
第 20 章:性能优化、可观测性、故障诊断与综合面试
**技术基线:**截至 2026 年 6 月,Redis Open Source 已发布 8.8。本章以 Redis 8.8 为参考,同时兼顾 Redis 6、7 的生产环境;涉及 Redis 8.6+、8.8+ 的能力会明确标注。(Redis)
1. 本章定位
前十九章分别讨论了数据结构、持久化、复制、高可用、缓存架构和分布式并发控制。本章负责将这些知识串成一套可执行的生产方法论:
- 先建立性能基线,知道系统在正常状态下应该是什么样。
- 从客户端、Redis、操作系统和拓扑四层建立观测能力。
- 根据证据排查故障,而不是看到 CPU 高就立刻扩容。
- 通过容量规划、压测、降级和容灾演练控制风险。
- 将这些内容转化为系统设计和面试回答能力。
Redis 性能问题很少只是“Redis 慢了”。一次请求的端到端耗时可能同时包含连接池等待、网络往返、服务器排队、命令执行、结果传输、反序列化和重试。因此,排障的核心不是背命令,而是完成以下闭环:
业务 SLO
↓
客户端端到端指标
↓
Redis 命令与资源指标
↓
操作系统、持久化与复制指标
↓
定位瓶颈并验证修复
↓
更新容量模型和告警阈值
2. 学习目标
完成本章后,你应该能够:
- 设计不误导结论的 Redis 基准测试,并解释
redis-benchmark的使用边界。 - 区分连接池等待、网络延迟、服务器排队和命令执行延迟。
- 使用
INFO、SLOWLOG、LATENCY、MEMORY等工具建立诊断证据链。 - 识别大 Key、热 Key、Swap、fork、COW、AOF fsync 和重试风暴。
- 按固定顺序排查 CPU 高、内存上涨、延迟抖动、复制延迟和频繁故障转移。
- 正确配置和观测 go-redis 连接池、超时、重试及 Pipeline。
- 为 Redis 设计 Prometheus 指标和 OpenTelemetry Trace。
- 完成 Redis 容量规划、压测、扩容、降级、安全加固和容灾演练。
2.1 本章边界与跳转
本章是性能优化、可观测性、故障诊断和综合面试的收束章节。这里会再次出现“Redis 为什么快”“Pipeline 是否越大越好”“连接池如何设置”“AOF 如何选择”“主从复制延迟如何排查”等题目,但它们是面试和排障入口,不替代前文主章节:高性能原理见[第 12 章](/blog/tech/Redis/12.Redis 高性能原理/),Go 客户端见[第 2 章](/blog/tech/Redis/02.使用 Go 操作 Redis/),持久化见[第 14 章](/blog/tech/Redis/14.RDB、AOF 与数据恢复/),复制与高可用见第 15 章到[第 17 章](/blog/tech/Redis/17.Redis Cluster 分片与高可用/),缓存架构和并发控制见第 18 章与第 19 章。
3. 核心概念
3.1 性能不是一个 QPS 数字
评价 Redis 性能至少要同时观察:
| 维度 | 典型指标 | 说明 |
|---|---|---|
| 吞吐量 | OPS、QPS、读写带宽 | 单独看吞吐量可能掩盖尾延迟 |
| 延迟 | p50、p95、p99、p999、最大值 | 平均值无法反映少量严重阻塞 |
| 错误 | 超时率、连接错误、命令错误、拒绝请求 | 重试可能暂时掩盖真实错误率 |
| 饱和度 | CPU、连接池等待、网络、内存、磁盘 | 判断是否已接近容量边界 |
| 数据效果 | 命中率、淘汰率、复制延迟 | 高 QPS 不等于业务效果好 |
| 可用性 | 故障转移、恢复时间、数据丢失窗口 | 性能优化不能牺牲业务目标 |
例如,某次压测从 10 万 QPS 提升到 15 万 QPS,但 p99 从 5 毫秒上升到 800 毫秒,对在线交易系统而言通常不是性能提升。
3.2 Redis 请求的延迟分解
端到端延迟可以近似拆成:
T_total =
T_app_queue
+ T_pool_wait
+ T_connect_auth_tls
+ T_request_network
+ T_server_queue
+ T_command
+ T_response_network
+ T_decode
+ T_retry
其中:
- 应用排队延迟:请求还没有调用 Redis,就已在 goroutine、任务队列或限流器中等待。
- 连接池等待:没有空闲连接,请求等待连接归还。
- 连接建立延迟:TCP、TLS、AUTH、客户端初始化。
- 网络延迟:请求和响应的传输、代理转发和跨可用区 RTT。
- 服务器排队延迟:前面的慢命令、长脚本或大响应占用了处理路径。
- 命令执行延迟:Redis 实际执行命令所花的时间。
- 客户端解码延迟:大响应的读取、内存分配和反序列化。
- 重试延迟:前一次调用超时后重新排队和执行。
SLOWLOG 记录的是命令实际执行时间,不包含客户端通信、发送响应等 I/O。因此,“客户端 p99 很高,但 SLOWLOG 为空”并不矛盾。(Redis)
3.3 两套容易混淆的延迟观测
Redis 中有两类相关但不同的机制:
INFO latencystats
按命令类型记录延迟百分位,默认输出 p50、p99 和 p999。它适合回答:
哪类命令整体变慢了?
Redis 8.8 的 INFO commandstats 还增加了按命令聚合的 slowlog_count、slowlog_time_ms_sum 和 slowlog_time_ms_max。(Redis)
LATENCY 监控子系统
记录 command、fork、expire-cycle、aof-write、aof-fsync-always 等内部事件,适合回答:
Redis 在哪个内部阶段发生了延迟尖峰?
它需要通过 latency-monitor-threshold 设置采样阈值;默认阈值为 0,即未启用事件采样。(Redis)
因此:
INFO latencystats → 按命令类型看延迟分布
SLOWLOG → 看超过阈值的具体命令
LATENCY → 看 Redis 内部阻塞事件
客户端 Trace → 看端到端耗时和连接池等待
3.4 基准测试的核心原则
redis-benchmark 适合快速测量某台机器、某种配置和某类命令的性能,但它不是完整的生产流量模型。官方文档明确指出:默认测试可能只访问单个 Key,默认依靠并发连接而不使用 Pipeline;同步单连接测试往往主要测到 RTT 和客户端开销,而不是 Redis 的最大处理能力。(Redis)
一个可信的基准测试应尽量匹配生产环境:
- Redis 版本、配置和持久化策略。
- 单机、Sentinel、Cluster 或代理拓扑。
- TLS、跨可用区网络和真实 RTT。
- Key 数量、Key 长度、Value 大小、数据类型和编码。
- 热点分布,而不是全部随机或全部单 Key。
- 读写比例、TTL 分布和淘汰策略。
- Pipeline 批次和连接数。
- 后台 RDB、AOF rewrite、过期和复制活动。
- 客户端序列化、反序列化和业务逻辑。
- 稳态、突发、长时间运行和故障恢复。
测试结论至少应包含:
配置 + 数据规模 + 流量模型 + 持久化策略
+ QPS + p50/p95/p99/p999 + 错误率
+ CPU/内存/网络/磁盘 + 持续时间
只报告“Redis 能达到 50 万 QPS”基本没有工程意义。
3.5 优化顺序
通常应按照以下顺序优化:
- 消除错误算法和阻塞操作:
KEYS、超大集合运算、长 Lua、全量返回。 - 处理大 Key、热 Key和流量倾斜。
- 减少网络往返:MGET、批量命令和适度 Pipeline。
- 控制请求和响应体积。
- 修正连接池、超时、重试和并发模型。
- 优化持久化、内存和操作系统配置。
- 再考虑垂直扩容或水平分片。
若一条 O(N) 命令正在扫描数百万个成员,增加连接数通常只会让更多请求排在它后面。
4. 命令与 Go 使用方法
4.1 INFO:获取全局状态
生产排障不建议只执行一个巨大 INFO 后人工浏览,应分区获取并保存时间序列:
redis-cli INFO server
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO persistence
redis-cli INFO replication
redis-cli INFO cpu
redis-cli INFO commandstats
redis-cli INFO latencystats
redis-cli INFO keyspace
重点字段包括:
| 分区 | 重点指标 |
|---|---|
| clients | connected_clients、blocked_clients、客户端缓冲区 |
| memory | used_memory、used_memory_rss、峰值、碎片、淘汰配置 |
| stats | instantaneous_ops_per_sec、命中、未命中、淘汰、过期、网络字节 |
| cpu | 主线程和整个进程的 user/sys CPU |
| commandstats | 各命令调用数、总耗时、平均耗时、失败和拒绝次数 |
| latencystats | 各命令 p50、p99、p999 |
| persistence | RDB/AOF 状态、fork、COW、rewrite 状态 |
| replication | 角色、连接状态、复制 offset、backlog |
| keyspace | Key 数、带 TTL 的 Key 数、平均 TTL |
INFO 字段会随 Redis 版本和配置变化,采集程序应允许未知字段和缺失字段,不能依赖固定行号。(Redis)
4.2 SLOWLOG:定位慢命令
redis-cli CONFIG GET slowlog-log-slower-than
redis-cli CONFIG GET slowlog-max-len
redis-cli SLOWLOG LEN
redis-cli SLOWLOG GET 20
每条慢日志通常包含:
- 日志 ID。
- Unix 时间戳。
- 命令执行微秒数。
- 命令参数。
- 客户端地址。
- 客户端名称。
建议为应用配置 ClientName,否则排查时只能看到地址,难以区分业务。
生产中调整慢日志阈值时:
# 示例:记录执行超过 5 毫秒的命令
redis-cli CONFIG SET slowlog-log-slower-than 5000
# 示例:增加保留条目数
redis-cli CONFIG SET slowlog-max-len 2048
阈值不能盲目设置成极小值。阈值过低可能产生大量记录,掩盖真正异常;托管服务也可能限制 CONFIG SET。SLOWLOG GET N 的复杂度与返回条目数 N 成正比。(Redis)
4.3 LATENCY:定位内部阻塞事件
# 先确认当前阈值
redis-cli CONFIG GET latency-monitor-threshold
# 示例:记录超过 10ms 的内部延迟事件
redis-cli CONFIG SET latency-monitor-threshold 10
redis-cli LATENCY LATEST
redis-cli LATENCY HISTORY command
redis-cli LATENCY GRAPH command
redis-cli LATENCY DOCTOR
LATENCY LATEST 返回:
- 事件名称。
- 最近事件时间。
- 最近一次延迟毫秒数。
- 实例启动或上次重置以来的最大值。(Redis)
还可以从客户端测量:
redis-cli --latency
redis-cli --latency-history
redis-cli --latency-dist
测量操作系统本身的调度延迟时,应在 Redis 所在主机上执行:
redis-cli --intrinsic-latency 100
该模式不连接 Redis,而是测量进程无法获得 CPU 时间的最长间隔;测试会占用一个核心,不应在不了解影响时长时间执行。(Redis)
4.4 MEMORY:分析内存组成
redis-cli MEMORY STATS
redis-cli MEMORY DOCTOR
redis-cli MEMORY USAGE user:10001
redis-cli MEMORY USAGE user:10001 SAMPLES 10
redis-cli MEMORY USAGE user:10001 SAMPLES 0
MEMORY USAGE 返回 Key、Value 及管理开销占用的内存。对集合类数据,默认通过抽样估算;SAMPLES 0 表示检查全部元素,可能显著增加诊断成本。(Redis)
MEMORY STATS 适合分析:
- 数据集内存与管理开销。
- 普通客户端和副本缓冲区。
- replication backlog。
- AOF buffer。
- allocator allocated、active、resident。
- allocator fragmentation。
- RSS overhead。
- 数据库字典和 rehash 临时内存。
它的价值是解释“内存花在哪里”,而不只是看到 used_memory。(Redis)
4.5 大 Key 与热 Key
# 按元素数量、字符串长度等发现大对象
redis-cli --bigkeys -i 0.01
# 按真实内存占用发现大对象
redis-cli --memkeys -i 0.01
# 综合内存、长度和分布
redis-cli --keystats --top 20 -i 0.01
# 限制命名空间
redis-cli --bigkeys --pattern 'order:*' -i 0.01
# 依赖 LFU 计数器
redis-cli --hotkeys -i 0.01
--bigkeys、--memkeys 和 --keystats 基于 SCAN 渐进遍历。它们不会像 KEYS * 一样一次性遍历全部 Key,但全库扫描仍会产生额外命令、CPU 和网络流量,应使用 -i 节流,并避开高峰。--bigkeys 偏向元素数量或逻辑长度,--memkeys 偏向实际内存,两者不能相互替代。(Redis)
传统 redis-cli --hotkeys 只有在 maxmemory-policy 使用 LFU 策略时才有效。(Redis)
Redis 8.6+ 提供了服务器侧 HOTKEYS,可按 CPU 时间和网络字节追踪热点。例如:
redis-cli HOTKEYS START \
METRICS 2 CPU NET \
COUNT 20 \
DURATION 60 \
SAMPLE 100
redis-cli HOTKEYS GET
redis-cli HOTKEYS STOP
该机制采用概率采样;较大的 SAMPLE 值降低开销,但也更容易漏掉热点。它与依赖 LFU 访问频率的 redis-cli --hotkeys 不是同一种机制。(Redis)
4.6 MONITOR:只做受控的短时诊断
# Linux 下限制为 5 秒
timeout 5s redis-cli MONITOR
MONITOR 会实时输出服务器处理的命令,适合确认某个异常客户端是否正在发送错误命令,但不适合持续监控。Redis 官方页面给出的示例中,一个 MONITOR 客户端就使吞吐量下降超过 50%;该数字不是所有环境的固定比例,但足以说明其高风险。(Redis)
生产使用原则:
- 只由受控运维身份执行。
- 限制持续时间。
- 避免高峰期。
- 避免将完整输出写入慢磁盘。
- 注意命令参数可能包含业务数据。
- 优先使用
INFO commandstats、SLOWLOG、Trace 和采样日志。
4.7 redis-benchmark 示例
建立无 Pipeline 基线
redis-benchmark \
-t get,set \
-c 200 \
-n 2000000 \
-d 1024 \
-r 1000000 \
--csv
测试与业务一致的 Pipeline
redis-benchmark \
-t get,set \
-c 200 \
-n 2000000 \
-d 1024 \
-r 1000000 \
-P 8 \
--csv
需要分别测试 -P 1、4、8、16、32,而不是只展示最高吞吐量。Pipeline 大小应接近业务实际能够聚合的批次。官方文档同样强调,使用远大于业务实际值的 Pipeline 会产生不真实的结果。(Redis)
压测前必须确认:
是否为专用测试实例
是否会覆盖真实 Key
是否开启与生产相同的 AOF/RDB
是否使用相同 TLS、网络和代理
是否预装等量数据
是否模拟热点和 TTL
客户端是否先于 Redis 达到 CPU 或网络瓶颈
4.8 go-redis:连接、超时、重试与可观测性
package redisdiag
import (
"context"
"crypto/tls"
"errors"
"fmt"
"time"
"github.com/redis/go-redis/extra/redisotel/v9"
"github.com/redis/go-redis/v9"
)
func NewClient(
ctx context.Context,
addr string,
username string,
password string,
tlsServerName string,
) (*redis.Client, error) {
var tlsConfig *tls.Config
if tlsServerName != "" {
tlsConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: tlsServerName,
}
}
rdb := redis.NewClient(&redis.Options{
Addr: addr,
Username: username,
Password: password,
ClientName: "order-api",
// 建立 TCP/TLS 连接的超时。
DialTimeout: 500 * time.Millisecond,
// 单次 socket 读写边界,不等于业务端到端超时。
ReadTimeout: 800 * time.Millisecond,
WriteTimeout: 800 * time.Millisecond,
// 所有可用连接忙时,等待连接的最长时间。
PoolTimeout: 250 * time.Millisecond,
PoolSize: 64,
MinIdleConns: 8,
MaxActiveConns: 96,
ConnMaxIdleTime: 5 * time.Minute,
ConnMaxLifetime: 30 * time.Minute,
// 这里只给出保守示例。非幂等命令不能盲目重试。
MaxRetries: 1,
MinRetryBackoff: 20 * time.Millisecond,
MaxRetryBackoff: 100 * time.Millisecond,
TLSConfig: tlsConfig,
})
if err := errors.Join(
redisotel.InstrumentTracing(rdb),
redisotel.InstrumentMetrics(rdb),
); err != nil {
_ = rdb.Close()
return nil, fmt.Errorf("instrument redis client: %w", err)
}
startupCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
if err := rdb.Ping(startupCtx).Err(); err != nil {
_ = rdb.Close()
return nil, fmt.Errorf("ping redis: %w", err)
}
return rdb, nil
}
这些具体数值只是示例,必须根据业务 SLO、网络 RTT、命令响应大小和压测结果确定。go-redis 当前版本提供自动连接池和 OpenTelemetry 的 Trace、Metrics 集成。(GitHub)
诊断快照示例:
func Inspect(
parent context.Context,
rdb *redis.Client,
sampleKey string,
) error {
ctx, cancel := context.WithTimeout(parent, 2*time.Second)
defer cancel()
info, infoErr := rdb.Info(
ctx,
"clients",
"memory",
"stats",
"persistence",
"replication",
"cpu",
"commandstats",
"latencystats",
).Result()
slowLogs, slowErr := rdb.SlowLogGet(ctx, 20).Result()
// 使用 Do 可以兼容尚未封装为强类型方法的命令。
latestLatency, latencyErr := rdb.Do(
ctx,
"LATENCY",
"LATEST",
).Result()
var keyBytes int64
var memoryErr error
if sampleKey != "" {
keyBytes, memoryErr = rdb.MemoryUsage(
ctx,
sampleKey,
10,
).Result()
switch {
case memoryErr == nil:
// 正常获取。
case errors.Is(memoryErr, redis.Nil):
// Key 不存在不是基础设施异常。
memoryErr = nil
keyBytes = 0
default:
memoryErr = fmt.Errorf(
"memory usage %q: %w",
sampleKey,
memoryErr,
)
}
}
pool := rdb.PoolStats()
fmt.Printf(
"info_bytes=%d slowlog=%d latency=%v key_bytes=%d "+
"pool_total=%d pool_idle=%d pool_pending=%d "+
"pool_wait_count=%d pool_wait_total=%s pool_timeouts=%d\n",
len(info),
len(slowLogs),
latestLatency,
keyBytes,
pool.TotalConns,
pool.IdleConns,
pool.PendingRequests,
pool.WaitCount,
time.Duration(pool.WaitDurationNs),
pool.Timeouts,
)
// 返回联合错误,同时保留已经成功采集的部分数据。
return errors.Join(
infoErr,
slowErr,
latencyErr,
memoryErr,
)
}
当前 go-redis 连接池统计包含总连接、空闲连接、等待次数、累计等待时间、等待超时以及待处理请求等指标。PoolSize、PoolTimeout 等参数的默认行为应以所固定的客户端版本为准,升级客户端时必须进行回归测试。(GitHub)
并发安全边界:
*redis.Client可以由多个 goroutine 共享,应按进程或目标实例复用,而不是每次请求新建。Pipeline对象不能被多个 goroutine 并发写入。- 每个并发任务应创建自己的 Pipeline,或使用一次性的
Pipelined闭包。 - 超时后的 Pipeline 可能涉及重发和重复执行风险,写命令必须考虑幂等性。(GitHub)
4.9 三层超时不能混为一谈
业务 Context 超时
ctx, cancel := context.WithTimeout(parent, 150*time.Millisecond)
defer cancel()
value, err := rdb.Get(ctx, key).Result()
它控制业务愿意等待的总时间,可能包含连接池等待、重试和命令执行。
PoolTimeout
表示连接全部繁忙时,客户端等待空闲连接的最长时间。
ReadTimeout / WriteTimeout
控制 socket 读写边界,防止连接长期卡住。
还要注意:
客户端超时不意味着 Redis 已经停止执行该命令。
命令一旦发送并被 Redis 接收,客户端即使取消 Context,服务器也可能继续执行。因此,对 INCR、Lua、事务和写 Pipeline 进行超时重试时,必须处理重复执行。
5. 典型业务场景
| 场景 | 适用方式 | 不适用情况 | 数据量要求 | 一致性要求 | 主要性能风险 | 替代或补充方案 |
|---|---|---|---|---|---|---|
| 普通对象缓存 | Cache Aside、TTL、批量 GET | 大对象频繁全量读写 | 单 Key 尽量可控 | 允许短暂旧值 | 击穿、雪崩、大 Value | 本地缓存、CDN |
| 热门内容 | 本地缓存 + Redis、多副本热点 | 单 Key 承担全部流量 | 热点需可拆分 | 通常最终一致 | 热 Key、单分片网络瓶颈 | CDN、进程缓存、请求合并 |
| 排行榜 | Sorted Set | 亿级成员频繁全量排名 | 按业务分榜、分周期 | 分数更新通常要求原子 | 大范围查询、热榜单 | OLAP、预计算 |
| 库存预扣 | Lua/Functions 原子校验扣减 | 将 Redis 当唯一账本 | Key 和脚本需同 Slot | 高一致性但仍需数据库对账 | 热 Key、重试重复扣减 | 数据库事务、消息事务 |
| 消息消费 | Streams 消费者组 | 超大消息和复杂路由 | 必须裁剪和分片 | 至少一次、消费幂等 | PEL 膨胀、慢消费者 | Kafka、Pulsar、RabbitMQ |
| 大规模分析 | 保存中间结果或近似统计 | 全库扫描、复杂 JOIN | 严格控制保留时间 | 一般较弱 | O(N) 命令阻塞 | 数据仓库、搜索引擎 |
| 跨地域强一致状态 | 作为局部缓存 | 直接承担全球强一致写入 | 与地域数量相关 | 强一致 | RTT、冲突、故障窗口 | 一致性数据库、地域分区 |
6. 底层实现
6.1 为什么慢命令会影响其他请求
Redis 的命令执行路径以事件循环为核心。现代 Redis 还包含 I/O 线程、持久化子进程、异步释放和后台任务,因此不能简单概括成“Redis 完全单线程”。
但对于大多数核心命令而言,同一分片上的命令执行仍存在明显的串行化特征:
慢命令执行 50ms
↓
该时间内后续命令等待
↓
大量客户端同时超时
↓
客户端重试
↓
队列进一步增长
因此,一条 50 毫秒的命令造成的影响,可能远大于它自己消耗的 50 毫秒。
6.2 INFO 的累计计数器
INFO commandstats 中的 calls、usec 等多数指标是进程启动后的累计值。监控系统必须计算时间窗口差值:
命令 QPS =
(calls_now - calls_before) / 时间间隔
命令 CPU 占比近似 =
Δcommand_usec / Δwall_time
不能直接对累计值设置“超过 100 万就告警”,否则实例运行得越久越容易误报。
6.3 SLOWLOG 的有界保存
SLOWLOG 不是磁盘审计日志,而是保存在内存中的有界历史记录:
- 超过阈值才记录。
- 最多保留
slowlog-max-len条。 - 新记录会覆盖旧记录。
- 只记录命令执行时间,不包含响应传输。
这使其开销可控,但也意味着故障发生较久后再查看,关键记录可能已被覆盖。
6.4 LATENCY 的事件时间序列
Redis 延迟监控为不同内部事件维护独立时间序列。官方文档说明,每个事件序列保留有限数量的样本,同一秒内多个尖峰会保留最大值。该设计适合低成本地发现尖峰,而不是精确记录每一次请求。(Redis)
6.5 大 Key 扫描的复杂度
| 工具或命令 | 复杂度或成本 | 适合回答的问题 |
|---|---|---|
MEMORY STATS | O(1) 获取服务器级统计 | 内存总体花在哪里 |
MEMORY USAGE | 与抽样元素数有关 | 某个 Key 占多少内存 |
SLOWLOG GET N | O(N) | 最近有哪些慢命令 |
LATENCY LATEST | O(1) | 最近有哪些内部尖峰 |
--bigkeys | 完整运行需扫描 Keyspace | 哪些 Key 元素最多 |
--memkeys | 扫描并估算内存 | 哪些 Key 实际最占内存 |
--hotkeys | SCAN + LFU 频率读取 | LFU 策略下哪些 Key 热 |
MONITOR | 随命令流量持续增加 | 此刻具体在执行什么 |
“基于 SCAN”不等于“零开销”。它只是将全量工作拆成多个较小批次,避免一次性阻塞。
6.6 fork 与 COW
RDB 保存和 AOF rewrite 通常需要创建子进程。fork() 本身要复制页表;数据集越大,页表和相关内核工作越多,主线程暂停时间可能越明显。
fork 后,父子进程最初共享物理内存页。当父进程继续处理写请求并修改页面时,操作系统通过 Copy-On-Write,写时复制 为被修改页面创建副本。
因此持久化期间的峰值内存不是简单的:
峰值内存 = used_memory
而更接近:
峰值内存 =
正常内存
+ fork/COW 增量
+ allocator/RSS 开销
+ 客户端及复制缓冲区
+ AOF 缓冲区
高写入率、随机更新和大对象修改通常会提高 COW 峰值。Redis 官方文档也指出,大数据集的 fork 可能造成可见的停顿;Redis 7.0+ 的 AOF 使用同一目录中的多文件结构,但 rewrite 仍需纳入资源规划。(Redis)
6.7 AOF fsync 为什么会导致抖动
AOF 大致包含:
命令追加到 AOF buffer
↓
write 写入操作系统
↓
fsync/fdatasync 推进到持久化介质
常见策略:
| 策略 | 延迟 | 数据安全窗口 | 适用性 |
|---|---|---|---|
appendfsync always | 最高,易受磁盘抖动影响 | 最小 | 需要明确评估后使用 |
appendfsync everysec | 性能与安全折中 | 通常约秒级窗口 | 常见选择 |
appendfsync no | 交给操作系统 | 窗口更不可控 | 缓存或可重建数据 |
磁盘繁忙、云盘抖动、AOF rewrite 与其他 I/O 竞争,都可能将磁盘问题传导到请求延迟。官方延迟诊断文档将 AOF write、pending fsync 和不同 fsync 策略列为重要延迟来源。(Redis)
6.8 版本差异
| 版本 | 与本章相关的重要变化 |
|---|---|
| Redis 6+ | ACL 成为推荐的细粒度认证方式;支持 TLS |
| Redis 7+ | AOF 使用多文件结构;Functions 等能力成熟 |
| Redis 7.4+ | MEMORY STATS 增加更多字典和 rehash 指标 |
| Redis 8.6+ | 提供原生 HOTKEYS CPU/网络热点跟踪 |
| Redis 8.8+ | INFO commandstats 增加慢日志聚合字段 |
7. 高性能、高并发、高可用分析
7.1 高性能
CPU
重点关注:
- O(N) 命令和集合基数。
- Lua/Function 执行时间。
- 热 Key 导致的单分片集中。
- 主线程 CPU 与后台进程 CPU。
- 过期、淘汰和主动碎片整理。
- TLS、压缩和客户端序列化。
CPU 高时,不能只看总进程 CPU。后台 RDB/AOF 子进程可能消耗多个核心,而真正决定命令延迟的往往是主线程是否被阻塞。
内存
重点关注:
- 数据集实际大小。
- Key 和对象管理开销。
- 内存分配器碎片。
- RSS 与
used_memory的差异。 - 客户端输出缓冲区。
- replication backlog。
- AOF、复制和 Lua/Function 缓存。
- fork/COW 峰值。
- 是否发生 Swap。
网络
Redis 常常在 CPU 耗尽之前先遇到网络瓶颈,尤其是:
- 大 Value。
- 大范围查询。
- 多副本复制。
- 跨可用区访问。
- TLS。
- 代理层转发。
- 热 Key 集中返回大量数据。
估算网络需求:
客户端网络带宽 ≈
QPS × 平均请求和响应字节数
总网络还需加入:
副本复制 + Cluster Bus + 迁移 + 备份流量
Pipeline 批次大小
Pipeline 减少 RTT,但批次不是越大越好。
过小:
- RTT 占比高。
- 系统调用和协议解析次数多。
- 吞吐量不足。
过大:
- 单连接占用时间变长。
- 请求在客户端等待聚批。
- 响应缓冲区和内存增长。
- 大批次中的慢命令导致队头阻塞。
- 超时后重复执行范围更大。
- p99 可能恶化。
正确方法是测试多个批次:
1 → 4 → 8 → 16 → 32 → 64
同时比较 QPS、p99、错误率、响应体积和连接池等待,选择满足 SLO 的最小批次,而不是吞吐量最高的批次。
7.2 高并发
连接池不是越大越好
连接池太小会产生等待;太大则可能带来:
- Redis 连接数和文件描述符上升。
- 更多并发请求进入服务器队列。
- 故障恢复时大量连接同时重建。
- TLS 握手和认证风暴。
- 客户端、代理和服务器内存增加。
可使用 Little 定律做初始估算:
并发中的 Redis 请求数 ≈ QPS × 平均响应时间
例如 20,000 QPS、平均端到端 5 毫秒:
20,000 × 0.005 ≈ 100 个并发请求
这只是初始估算,还应加入突发、p99、多个实例竞争和 Pipeline 占用因素,并通过压测验证。
重试风暴
典型过程:
Redis 延迟上升
↓
大量客户端同时超时
↓
每个请求立即重试 3 次
↓
Redis 收到原流量的数倍请求
↓
延迟进一步上升
↓
更多超时和重试
防护措施:
- 只重试可安全重试的命令。
- 指数退避和随机抖动。
- 限制单请求重试次数。
- 设置全局重试预算。
- 熔断、并发上限和排队上限。
- 对热点回源使用 singleflight。
- 非关键功能快速失败或降级。
- 记录“尝试次数”和“逻辑请求数”,避免重试掩盖流量。
7.3 高可用
故障转移期间客户端可能经历:
- 旧连接断开。
- DNS、Sentinel 或 Cluster 拓扑更新。
- 新主节点尚未完成提升。
READONLY、MOVED、连接重置等错误。- 连接池集中重建。
- 写请求重试。
- 副本数据落后导致少量已确认写入丢失。
因此高可用不仅是“Redis 能选出新主节点”,还包括:
客户端发现时间
+ 连接恢复时间
+ 重试行为
+ 幂等处理
+ 数据一致性影响
+ 业务降级时间
压测必须包含故障切换,不能只测稳定主节点。
8. 常见错误与生产事故
8.1 CPU 突然飙高
现象
- Redis 主线程 CPU 接近单核上限。
- p99 快速上升。
- 连接池等待和超时增加。
- 总 QPS 可能上升,也可能下降。
根因
- 新代码引入
KEYS、大集合运算或长 Lua。 - 热 Key 将流量集中到一个分片。
- 大量 Key 同时过期。
- 淘汰、主动碎片整理或模块查询开销。
- 客户端超时后重试放大流量。
排查顺序
- 看业务流量、错误率、部署和重试次数是否变化。
- 对比
INFO commandstats的调用量和 CPU 增量。 - 查看
INFO latencystats和 SLOWLOG。 - 扫描大 Key、热 Key。
- 检查
LATENCY LATEST的command、expire-cycle、eviction-cycle。 - 检查 RDB/AOF 子进程和操作系统 CPU steal。
修复方案
- 下线或限流异常接口。
- 删除 O(N) 路径,改为分页、预计算或异步处理。
- 拆分热 Key,增加本地缓存或请求合并。
- 使用 TTL 抖动。
- 限制重试并启用熔断。
如何预防
- 对命令复杂度和集合上限进行代码审查。
- 监控按命令分类的 QPS、CPU 和 p99。
- 上线前回放真实流量。
- 对热 Key 和重试次数设置告警。
8.2 used_memory 持续上涨
现象
used_memory上涨。- RSS 可能同步或更快上涨。
- 开始淘汰,甚至 OOM。
- fork 时内存突然放大。
根因
- Key 数量或 Value 持续增长。
- TTL 丢失或过期时间过长。
- Streams、列表、集合没有裁剪。
- 客户端输出缓冲区增长。
- replication backlog 或 AOF buffer 增长。
- 内存碎片。
- fork/COW。
- 删除了 Key,但 allocator 尚未立即归还内存给操作系统。
排查顺序
- 对比 Key 数、数据集内存和内存管理开销。
- 看
MEMORY STATS中 dataset、clients、replication、AOF。 - 比较
used_memory、RSS、allocator allocated/active/resident。 - 使用
--keystats、--memkeys按命名空间分析。 - 检查无 TTL Key 和业务增长。
- 对齐
rdb_bgsave_in_progress、AOF rewrite 与内存峰值。 - 检查
/proc、vmstat是否发生 Swap。
修复方案
- 恢复 TTL 和集合裁剪。
- 拆分或删除大 Key,必要时使用
UNLINK。 - 控制客户端缓冲区和慢消费者。
- 增加分片或内存。
- 调整持久化时机,降低 COW 峰值。
- 对可重建数据设置合理淘汰策略。
如何预防
- 按业务命名空间记录 Key 数、平均内存和增长率。
- 容量规划包含 COW、碎片和缓冲区。
- 对无 TTL Key 比例、淘汰量和 RSS 设置告警。
8.3 客户端 p99 抖动,但 SLOWLOG 为空
现象
- 应用侧 Redis 调用从 5 毫秒升到 300 毫秒。
- SLOWLOG 没有对应命令。
- Redis CPU 可能并不高。
根因
- 连接池等待。
- 网络丢包、跨区抖动或代理排队。
- fork、AOF fsync、Swap。
- 响应很大,服务器执行快但传输慢。
- Go 进程 GC 或调度抖动。
- 超时后的重试拉长总耗时。
排查顺序
- 查看客户端 Span,拆分 pool wait 和命令总耗时。
- 查看
PoolStats的等待次数、时间和超时。 - 对比客户端和 Redis 所在网络的 RTT。
- 查看
INFO latencystats。 - 查看
LATENCY LATEST中 fork、AOF、expire、command。 - 检查 Redis Swap、磁盘和宿主机调度。
- 检查响应字节数和客户端 GC。
修复方案
- 修正连接池和并发上限。
- 减少大响应。
- 修复网络或代理瓶颈。
- 处理 fork、磁盘和 Swap。
- 调整 Context、socket 和 PoolTimeout 的层级。
如何预防
- 同时监控客户端和服务器。
- Trace 中记录数据库命令、节点、重试次数和响应大小。
- 不把 SLOWLOG 当成唯一延迟证据。
8.4 主从复制延迟持续扩大
现象
- 副本读取旧值。
- 主副本 offset 差距扩大。
- 故障转移后数据丢失窗口增加。
- 副本可能频繁全量同步。
根因
- 主节点写入速度超过副本应用能力。
- 主副本网络带宽或延迟异常。
- 副本 CPU、磁盘或内存不足。
- 大 Key 写入占用复制链路。
- backlog 太小,短暂断线后无法部分重同步。
- 副本同时承担大量慢查询。
- fork、AOF 或 Swap 使副本停顿。
排查顺序
- 比较主副本复制 offset 和变化速率。
- 检查复制链路状态、断线和重连次数。
- 对比主副本 CPU、网络、磁盘和 Swap。
- 检查是否发生全量同步。
- 检查写入带宽和大 Value。
- 检查副本是否承担重查询。
- 检查 backlog 大小能否覆盖典型断线窗口。
修复方案
- 增强副本资源和网络。
- 扩大合理的 replication backlog。
- 拆分写热点和大 Value。
- 降低副本查询负载。
- 增加分片。
- 对一致性敏感读取改为主节点或增加版本校验。
如何预防
- 监控 offset lag、复制断开、全量同步次数。
- 故障演练验证 RPO,而不是只验证能否完成选主。
8.5 Sentinel 或 Cluster 频繁故障切换
现象
- 主节点并未真正宕机,却频繁被判断失败。
- 客户端不断断连和重建连接。
- 大量
READONLY、重定向或超时错误。
根因
- 节点被慢命令、fork、Swap 或磁盘阻塞。
- 网络丢包或安全组变更。
- 故障检测超时相对环境过紧。
- Sentinel 数量、quorum 或网络布局不合理。
- Cluster 节点间总线受阻。
- 宿主机资源超卖。
- DNS、NAT 或代理连接不稳定。
排查顺序
- 按时间对齐 Sentinel/Cluster、Redis、客户端和操作系统日志。
- 判断是进程退出、网络不可达还是事件循环停顿。
- 查看故障前的 CPU、fork、AOF、Swap 和延迟事件。
- 检查节点间网络和时钟。
- 检查 quorum、超时和拓扑。
- 检查客户端是否在切换期间制造连接或重试风暴。
修复方案
- 优先修复资源和网络根因。
- 根据真实延迟分布调整检测参数。
- 隔离 Sentinel 和 Redis 的故障域。
- 对客户端增加退避、抖动和重试预算。
- 减少单实例数据量及 fork 时间。
如何预防
- 定期进行真实故障演练。
- 同时测量故障检测、选主、客户端恢复和业务恢复时间。
8.6 连接池耗尽并触发重试风暴
现象
- Redis 本身 CPU 尚可,但应用大量超时。
PoolStats中等待和超时快速增加。- goroutine 数量、请求队列和内存增长。
- Redis QPS 随重试突然增加。
根因
- 连接池过小。
- 单命令或大 Pipeline 长时间占用连接。
- 请求没有端到端超时。
- 下游变慢后上游仍无限接收请求。
- 超时后立即重试。
- 每个请求重复创建客户端或连接。
排查方法
- 观测 pending requests、WaitCount、WaitDuration 和 Timeouts。
- 对比业务并发数、PoolSize、MaxActiveConns。
- 检查 Pipeline 大小和阻塞命令。
- 区分逻辑请求数与实际 Redis 尝试次数。
- 查看 goroutine 和应用队列。
修复方案
- 设置业务超时和队列上限。
- 调整连接池,但不能只靠无限扩大。
- 缩小 Pipeline 或隔离长命令。
- 加入并发限制、熔断和负载丢弃。
- 重试使用退避、抖动和预算。
如何预防
- 将连接池等待作为一等指标。
- 压测时覆盖下游变慢和超时场景。
8.7 BGSAVE 或 BGREWRITEAOF 期间延迟尖峰
现象
- 周期性 p99 尖峰。
- 尖峰与 RDB 保存或 AOF rewrite 对齐。
- RSS、磁盘写入和系统 CPU 同时上升。
根因
- 大实例 fork 复制页表。
- 写入率高导致大量 COW。
- 子进程与主进程争夺 CPU、内存带宽和磁盘。
- 云盘 fsync 抖动。
- Transparent Huge Pages 放大 COW 成本。
排查方法
- 查看
latest_fork_usec、RDB/AOF 状态。 - 查看
LATENCY LATEST的 fork 和 AOF 事件。 - 对比 RSS、COW 统计、磁盘延迟和写入率。
- 检查 THP 和 Swap。
- 比较不同分片大小的 fork 时间。
修复方案
- 降低单分片数据量。
- 使用更快、延迟更稳定的存储。
- 错开备份和其他 I/O 任务。
- 控制 rewrite 期间写入峰值。
- 评估持久化策略与 RPO。
- 按官方建议配置操作系统。
如何预防
- 容量规划包含 fork 和 COW。
- 压测中主动触发 BGSAVE、BGREWRITEAOF。
8.8 大 Key 或热 Key 拖垮单分片
现象
- Cluster 整体资源充足,但一个分片 CPU 或网络饱和。
- 某类命令耗时集中在少数 Key。
- 删除、迁移、复制或故障恢复耗时异常。
根因
- 单个 Hash、List、Set、ZSet 或 Stream 无边界增长。
- 所有热门请求命中同一个 Key。
- Hash Tag 将大量 Key 固定在同一 Slot。
- 大 Value 频繁全量序列化。
- 缓存重建集中访问数据库和 Redis。
排查方法
--bigkeys、--memkeys、--keystats。--hotkeys或 Redis 8.6+HOTKEYS。- 按分片比较 CPU、网络、Key 数和 Slot。
- 结合业务日志确认访问模式。
修复方案
- 按时间、租户、用户或桶拆分。
- 大对象分字段或分块存储。
- 热点使用本地缓存、复制 Key、请求合并。
- 使用
UNLINK渐进删除。 - 调整 Hash Tag 和 Slot 分布。
如何预防
- 为单 Key 字节数、元素数和 QPS 设置业务上限。
- 在数据模型设计阶段明确裁剪规则。
9. 方案选型与权衡
9.1 诊断工具选型
| 工具 | 主要用途 | 开销 | 优点 | 局限 | 生产建议 |
|---|---|---|---|---|---|
INFO | 全局指标、命令和资源统计 | 低 | 覆盖广、易采集 | 多为累计值,字段会变化 | 持续采集 |
SLOWLOG | 具体慢命令 | 低到中 | 可看到命令、耗时和客户端 | 不含网络和队列延迟 | 长期开启合理阈值 |
INFO latencystats | 按命令延迟分位 | 低 | 适合时间序列 | 不直接给出业务调用链 | 持续采集 |
LATENCY | fork、AOF、过期等内部尖峰 | 低 | 能解释内部停顿 | 需配置阈值、只记录尖峰 | 按 SLO 设置 |
MEMORY STATS | 服务器内存组成 | 低 | 能区分数据和开销 | 不能直接定位业务 Key | 持续采集 |
--keystats | 大 Key 和分布 | 中 | 能定位具体 Key | 全库扫描仍有成本 | 节流、低峰执行 |
HOTKEYS | 热点定位 | 中,可采样 | 能定位 CPU/网络热点 | 版本和配置有要求 | 短时受控使用 |
MONITOR | 实时命令流 | 高 | 直接看到请求 | 明显影响性能和数据安全 | 最后手段、严格限时 |
| OpenTelemetry | 客户端端到端调用链 | 中 | 能看到池等待、重试和上游 | 需要采样和字段治理 | 对关键链路启用 |
9.2 连接池和 Pipeline 权衡
| 决策 | 过小 | 过大 | 正确依据 |
|---|---|---|---|
| PoolSize | 等待、超时 | 连接和并发膨胀 | QPS、延迟、并发与压测 |
| PoolTimeout | 过早失败 | 请求长时间堆积 | 业务总超时预算 |
| MinIdleConns | 突发时建连慢 | 空闲连接占资源 | 建连成本与突发流量 |
| Pipeline 批次 | RTT 开销高 | 排队、缓冲和重试范围大 | QPS 与 p99 的共同拐点 |
| ReadTimeout | 正常请求误超时 | 故障发现太慢 | 响应体积、网络、p99 |
| MaxRetries | 短故障恢复弱 | 重试风暴和重复执行 | 幂等性、错误类型、预算 |
9.3 Prometheus 指标设计
Prometheus 官方建议在线服务至少监控请求数、错误和延迟,并同时从客户端和服务器侧观测;缓存还应监控查询数、命中数和总体延迟。(普罗米修斯)
建议指标:
客户端
redis_client_commands_total{command,status}
redis_client_command_duration_seconds{command}
redis_client_retries_total{command,reason}
redis_client_pool_wait_total
redis_client_pool_wait_duration_seconds
redis_client_pool_timeouts_total
redis_client_pool_connections{state}
redis_client_request_bytes_total
redis_client_response_bytes_total
cache_requests_total{result="hit|miss|error"}
Redis 服务端
redis_commands_processed_total
redis_command_calls_total{command}
redis_command_cpu_seconds_total{command}
redis_command_latency_seconds{command}
redis_connected_clients
redis_blocked_clients
redis_used_memory_bytes
redis_used_memory_rss_bytes
redis_memory_fragmentation_ratio
redis_evicted_keys_total
redis_expired_keys_total
redis_network_bytes_total{direction}
持久化与复制
redis_fork_duration_seconds
redis_rdb_last_save_success
redis_aof_rewrite_in_progress
redis_aof_last_rewrite_success
redis_replication_offset_lag
redis_replication_link_up
redis_full_syncs_total
redis_role_changes_total
标签需要控制基数:
- 可以使用:环境、集群、节点、角色、命令、状态。
- 谨慎使用:数据库编号、业务模块。
- 不应使用:完整 Key、用户 ID、订单 ID、Trace ID。
延迟指标优先使用可聚合的 Histogram;Prometheus 当前文档建议在条件允许时优先考虑原生直方图,并指出 Summary 的分位值无法在多个实例间正确聚合。(普罗米修斯)
9.4 OpenTelemetry 的作用
OpenTelemetry Trace 适合回答:
哪个 HTTP 请求调用了 Redis?
调用前在应用中排队多久?
Redis 调用是否发生重试?
调用了哪个命令和节点?
Redis 是整个调用链的主瓶颈吗?
一个 Span 通常包含名称、开始与结束时间、状态、属性和事件,并通过 Context Propagation 与上游请求关联。(OpenTelemetry)
Redis Span 不应记录完整 Value,也不应默认记录敏感 Key。可以记录:
db.system = redis
db.operation.name = GET
server.address = redis.internal
server.port = 6379
error.type
retry.count
pipeline.command_count
response.size_bucket
9.5 容量规划
内存容量
M_peak =
M_dataset
+ M_key_and_object_overhead
+ M_allocator_fragmentation
+ M_client_buffers
+ M_replication_backlog
+ M_aof_buffers
+ M_module_or_script_overhead
+ M_cow_peak
+ M_operational_reserve
不能用“Redis 机器有 32 GB,所以 maxmemory 配 31 GB”这种方法。必须先通过真实数据测量每个 Key 的平均和高分位内存,再加入 COW、碎片、客户端、复制及操作系统余量。
CPU 容量
使用满足目标 p99 和错误率时的可持续吞吐量,而不是压测中最终崩溃前的最大 QPS:
生产目标负载
<
单分片可持续容量 × 分片数量 × 安全系数
还要按 N-1 场景计算:一个主分片故障时,剩余资源能否承受迁移和恢复流量。
网络容量
网络峰值 =
业务请求与响应
+ 主从复制
+ Cluster Bus
+ 全量同步
+ Slot 迁移
+ RDB/AOF 备份
连接容量
需要同时考虑:
- 应用实例数。
- 每实例连接池。
- 发布期间新旧实例重叠。
- 故障时集中重连。
- Sentinel、监控、运维和副本连接。
- Redis 与代理的最大连接数及文件描述符。
9.6 压测、扩容、降级和容灾演练
完整测试矩阵至少包含:
| 测试 | 目标 |
|---|---|
| 预热测试 | 消除冷连接、冷页和缓存未命中的干扰 |
| 稳态测试 | 验证目标 QPS 下的长期 p99 |
| 阶梯加压 | 找到吞吐、延迟和资源拐点 |
| 突发测试 | 验证连接池、排队和限流 |
| 浸泡测试 | 发现内存泄漏、碎片和 TTL 问题 |
| 持久化测试 | 验证 BGSAVE、AOF rewrite 和 fsync |
| 故障测试 | 验证主从切换、重连和幂等 |
| 恢复测试 | 验证流量恢复时不会二次冲击 |
| 数据恢复 | 验证 RDB/AOF 备份真的可恢复 |
扩容选择
垂直扩容适合:
- 单实例数据量仍可控。
- 暂时需要快速缓解 CPU、内存或网络压力。
- 热点尚不能合理拆分。
水平分片适合:
- 数据量、QPS 或网络持续增长。
- 单分片 fork、恢复时间不可接受。
- 可以接受跨 Slot 限制和更复杂运维。
降级策略
- 返回本地缓存或允许的旧数据。
- 对非关键缓存写入快速失败。
- 关闭高成本统计、排行榜或推荐功能。
- 对缓存重建进行 singleflight。
- 限制大查询和大响应。
- 对非核心接口进行负载丢弃。
- 缓存不可用时保护数据库,而不是无上限回源。
容灾演练
演练必须记录:
故障注入时间
故障检测时间
选主完成时间
客户端恢复时间
业务恢复时间
实际数据丢失窗口
积压清空时间
是否发生重试风暴
是否需要人工操作
10. 高频面试题
10.0 重复题目的使用方式
本章的面试题有意覆盖前十九章的高频考点,但不再把每个概念完整重讲一遍。遇到重复题时,先用本章的短回答组织面试表达,再回到主章节补细节:
| 重复主题 | 本章用途 | 主章节 |
|---|---|---|
| Redis 为什么快、为什么仍会慢 | 面试短答和排障入口 | [第 12 章](/blog/tech/Redis/12.Redis 高性能原理/) |
| 连接池、超时、重试、Pipeline | 客户端观测和容量判断 | [第 2 章](/blog/tech/Redis/02.使用 Go 操作 Redis/)、[第 9 章](/blog/tech/Redis/09.Pipeline、事务、WATCH、Lua 与 Functions/) |
| 大 Key、热 Key、内存上涨 | 诊断路径和指标选择 | [第 3 章](/blog/tech/Redis/03.Key 设计、TTL 与生命周期管理/)、第 13 章 |
| AOF、RDB、fork、COW | 延迟尖峰和恢复风险入口 | [第 14 章](/blog/tech/Redis/14.RDB、AOF 与数据恢复/) |
| 复制延迟、故障转移、分片扩容 | 综合排障和容量规划入口 | 第 15 章、[第 16 章](/blog/tech/Redis/16.Sentinel 高可用/)、[第 17 章](/blog/tech/Redis/17.Redis Cluster 分片与高可用/) |
| 缓存雪崩、热 Key、回源保护 | 系统设计题入口 | 第 18 章 |
| Lua、锁、限流、幂等、延迟任务 | 并发控制和一致性入口 | 第 19 章 |
10.1 Redis 系统设计题
系统设计题一:设计百万 QPS 热门内容缓存
问题
设计一个热门视频详情缓存。峰值一百万 QPS,少量视频可能占总流量的 30%,允许秒级旧数据,要求 Redis 故障不能压垮数据库。
推荐回答
简洁回答:
我会使用 CDN、本地缓存和 Redis 组成多级缓存,Redis 采用 Cache Aside;对热点 Key 使用本地缓存、singleflight、逻辑过期和热点复制,避免所有请求集中到一个分片。Redis 故障时通过限流、旧值和负缓存保护数据库。
详细设计:
-
请求路径
CDN ↓ Go 进程本地缓存 ↓ Redis Cluster ↓ 数据库 -
Key 设计
video:{videoID}:detail:v3 -
普通缓存
- 物理 TTL 加随机抖动。
- 数据库更新后删除缓存或通过 CDC 失效。
- 空结果进行短 TTL 缓存。
-
热点处理
- 热 Key 在每个应用实例做短期本地缓存。
- singleflight 合并并发回源。
- 允许时使用逻辑过期并异步刷新。
- 必要时将热点复制为多个 Key,由客户端随机读取。
- 大对象拆分为基础信息和低频扩展字段。
-
故障保护
- Redis 超时短于 HTTP 总预算。
- 限制数据库回源并发。
- 返回旧缓存或降级结果。
- 熔断 Redis 和数据库。
- 禁止每个请求多次立即重试。
-
观测
- 各层命中率。
- 热 Key QPS。
- Redis 分片 CPU、网络和 p99。
- singleflight 合并数。
- 回源数据库 QPS。
- 降级比例。
-
容量
- 按高分位 Value 大小计算网络。
- 按 N-1 分片承载能力规划。
- 压测 Redis 故障后的数据库保护能力。
面试官追问
- 热点复制后如何失效?
- 本地缓存如何避免长时间旧数据?
- Redis 整体不可用时如何防止缓存雪崩?
常见错误回答
- 只说“上 Redis Cluster”。
- 认为增加分片就能自动分散单个热 Key。
- Redis 出错时所有请求直接访问数据库。
- 只监控整体命中率,不监控热 Key。
评分点
- 初级:知道 Cache Aside、TTL 和缓存击穿。
- 中级:能设计本地缓存、singleflight 和降级。
- 高级:能分析热 Key、网络容量、N-1 和数据一致性。
系统设计题二:设计秒杀库存预扣系统
问题
设计十万并发用户抢购一千件商品的库存预扣系统,要求不超卖、支持重复请求、最终与数据库一致。
推荐回答
简洁回答:
Redis 用于入口削峰和原子预扣,但数据库仍是最终账本。使用 Lua 或 Functions 在同一 Slot 内原子校验库存、记录用户和生成预扣结果;请求带幂等 ID,成功事件写入可靠消息链路,由订单服务落库并进行对账和补偿。
核心数据:
stock:{sku}:available
stock:{sku}:buyers
request:{requestID}:result
stream:{sku}:orders
Lua/Function 原子完成:
- 查询幂等结果。
- 判断用户是否已购买。
- 判断库存是否大于零。
- 扣减库存。
- 记录用户。
- 写入结果和事件。
- 返回明确状态。
必须考虑:
- Cluster 中相关 Key 使用 Hash Tag 保证同 Slot。
- 客户端超时后可能已经扣减,因此按 request ID 查询结果,不能直接再次扣减。
- 消费端至少一次投递,数据库写入需要唯一约束。
- Redis 主从切换可能丢失尚未复制的写,业务需要数据库对账。
- 预扣超时未支付,需要归还库存,但必须使用状态机避免重复归还。
- Redis 不应是唯一订单记录。
面试官追问
- Lua 执行成功但客户端超时怎么办?
- Redis 主节点故障后少量预扣记录丢失怎么办?
- 如何避免单 SKU 热 Key 打满一个分片?
常见错误回答
GET后在 Go 中判断,再执行DECR。- 认为 Redis 单命令原子就能保证整个订单系统强一致。
- 超时后直接重试扣减。
- 不设计对账和补偿。
评分点
- 初级:知道 Lua 原子扣减。
- 中级:能处理幂等、消息消费和库存归还。
- 高级:能说明复制故障窗口、账本边界和热 Key 处理。
系统设计题三:设计延迟关单系统
问题
订单创建 30 分钟未支付需要自动关闭。峰值每分钟产生百万订单,允许任务重复但不能漏关,如何设计?
推荐回答
简洁回答:
可以用分片 Sorted Set 保存执行时间,但不能只靠定时
ZRANGEBYSCORE后直接删除。应采用“领取、持久化处理、ACK、超时重试”模型,或使用专业延迟消息系统。Redis 方案需要分桶、Lua 原子领取、幂等状态机和数据库兜底扫描。
Redis 方案:
delay:{shard}:yyyyMMddHH
score = 执行时间戳
member = 订单 ID
处理过程:
- 多个时间桶和分片,避免一个超大 ZSet。
- 消费者读取到期订单。
- Lua 原子地将订单从待处理集合移动到处理中集合。
- 处理前查询数据库订单状态。
- 使用条件更新关闭订单。
- 成功后删除处理中记录。
- 超时未 ACK 的任务重新投递。
- 数据库定期扫描过期未关闭订单兜底。
选择专业 MQ 的情况:
- 延迟消息量非常大。
- 需要长期堆积。
- 需要成熟的重试、死信、消费监控和跨地域能力。
- 团队已有可靠消息基础设施。
面试官追问
- 消费者取出后宕机怎么办?
- 如何扩容而不重复或漏处理?
- 为什么不能只用 Key 过期通知?
常见错误回答
- 用每秒
KEYS order:*扫描。 - 依赖过期通知保证可靠投递。
ZRANGE后直接ZREM,不设计崩溃恢复。- 认为重复消费一定可以完全避免。
评分点
- 初级:知道 ZSet 按时间调度。
- 中级:能设计原子领取、幂等和重试。
- 高级:能进行 Redis 与专业 MQ 的边界权衡。
10.2 Redis 综合面试快问快答
快问 1:Redis 为什么通常很快,却仍会出现百毫秒延迟?
**推荐回答:**Redis 的内存访问、紧凑数据结构、事件驱动和低协议开销使普通命令很快,但慢命令、长脚本、热 Key、连接池等待、网络、大响应、fork、AOF fsync 和 Swap 都能制造尾延迟。
**面试官追问:**为什么平均延迟正常而 p99 很高?
**常见错误回答:**Redis 是单线程,所以一定慢;Redis 在内存里,所以不会慢。
**评分点:**中级候选人应能区分命令执行和端到端延迟;高级候选人应给出完整证据链。
快问 2:如何评价 Redis 性能?
**推荐回答:**至少同时看吞吐量、p50/p95/p99/p999、错误率和资源饱和度,再结合命中率、淘汰、复制延迟和业务 SLO。最大 QPS 不能单独代表生产容量。
**面试官追问:**为什么不能只看平均延迟?
**常见错误回答:**只看 instantaneous_ops_per_sec。
**评分点:**高级回答会强调稳态、突发、N-1 和恢复阶段。
快问 3:命令延迟、网络延迟和排队延迟有什么区别?
**推荐回答:**命令延迟是 Redis 实际执行命令的时间;网络延迟包含请求和响应传输;排队延迟可能发生在应用队列、连接池或Redis前序命令之后。客户端耗时通常是三者及解码、重试的总和。
**面试官追问:**SLOWLOG 能看到哪一部分?
**常见错误回答:**客户端统计的 100 毫秒就是 Redis 执行了 100 毫秒。
**评分点:**能画出端到端延迟公式属于高级回答。
快问 4:SLOWLOG 为空,能说明 Redis 没问题吗?
**推荐回答:**不能。SLOWLOG 不包含连接池等待、网络、发送响应等时间,也可能因阈值太高或记录被覆盖而看不到问题。还要检查客户端 Trace、PoolStats、INFO latencystats 和 LATENCY。
**面试官追问:**大响应会不会进入 SLOWLOG?
**常见错误回答:**SLOWLOG 为空就一定是应用问题。
**评分点:**高级回答应提到 fork、fsync 和 Swap。
快问 5:排障时最常用哪些 INFO 分区?
推荐回答:clients、memory、stats、cpu、commandstats、latencystats、persistence、replication 和 keyspace。需要取时间窗口差值,而不是只看单次快照。
**面试官追问:**为什么采集程序不能依赖固定字段?
**常见错误回答:**只执行 INFO memory。
**评分点:**能按故障类型选择分区并计算 rate 属于中高级。
快问 6:如何用 commandstats 找 CPU 消耗最大的命令?
**推荐回答:**分别采集两个时间点的 calls 和 usec,计算窗口增量,再按 Δusec 排序。usec_per_call 高表示单次重,calls 增长快表示频率高,两者都可能消耗大量 CPU。
**面试官追问:**为什么累计 usec 最大的不一定是当前问题?
**常见错误回答:**直接看实例启动以来总量。
**评分点:**高级回答会结合 SLOWLOG、热 Key 和部署时间。
快问 7:INFO latencystats 与 LATENCY LATEST 有何区别?
**推荐回答:**前者按命令类型输出延迟百分位;后者记录超过阈值的内部事件,如 command、fork、expire-cycle 和 AOF write。一个回答“哪类命令慢”,一个回答“Redis 内部什么阶段发生尖峰”。
**面试官追问:**两者默认是否都启用?
**常见错误回答:**认为是同一份数据的两种展示。
**评分点:**能说明 latency monitor threshold 的候选人更成熟。
快问 8:为什么不建议长时间使用 MONITOR?
**推荐回答:**它会复制并向客户端发送几乎所有命令流,消耗 CPU、网络和输出缓冲区,还可能暴露业务参数。只应在受控环境短时间采样。
**面试官追问:**替代工具是什么?
**常见错误回答:**把 MONITOR 当生产审计日志。
**评分点:**高级回答会优先选择 commandstats、SLOWLOG 和 Trace。
快问 9:MEMORY USAGE 与 MEMORY STATS 有什么区别?
**推荐回答:**前者回答某个 Key 及其管理开销占多少内存;后者回答整个实例的数据集、客户端、复制、AOF、allocator 和碎片等内存组成。
面试官追问:SAMPLES 0 有什么风险?
**常见错误回答:**认为 MEMORY USAGE 只返回 Value 字节长度。
**评分点:**高级回答会区分逻辑长度、序列化大小和实际分配内存。
快问 10:大 Key 与热 Key 有什么区别?
**推荐回答:**大 Key 指单个对象字节数或元素数过大,影响操作、复制、迁移、删除和恢复;热 Key 指访问频率或 CPU、网络占比过高,可能很小但流量集中。两者可能重叠,也可能完全独立。
**面试官追问:**分别如何解决?
**常见错误回答:**把访问量大和占用内存大当成同一问题。
**评分点:**高级回答会讨论拆分、本地缓存、热点复制和 Slot 倾斜。
快问 11:redis-cli --hotkeys 和 Redis 8.6+ HOTKEYS 有何区别?
推荐回答:--hotkeys 读取 LFU 计数,因此要求 LFU 淘汰策略;Redis 8.6+ 原生 HOTKEYS 能通过概率采样按 CPU 和网络字节追踪热点。
**面试官追问:**采样比例如何权衡?
**常见错误回答:**认为所有 Redis 版本都支持原生 HOTKEYS。
**评分点:**能明确版本边界属于加分项。
快问 12:如何避免 redis-benchmark 得出错误结论?
**推荐回答:**匹配生产拓扑、网络、TLS、持久化、Value 大小、Keyspace、热点、读写比、Pipeline 和连接数;同时观测 p99、错误率和客户端是否先达到瓶颈。
**面试官追问:**为什么默认单 Key 可能误导?
**常见错误回答:**直接用默认命令结果作为生产容量。
**评分点:**高级回答会加入稳态、浸泡和故障测试。
快问 13:Pipeline 是否越大越好?
**推荐回答:**不是。Pipeline 减少 RTT,但过大会增加聚批等待、连接占用、响应缓冲、队头阻塞和超时后的重复执行范围。应选择满足 SLO 的最小有效批次。
**面试官追问:**如何选择批次?
**常见错误回答:**只选择 QPS 最大的批次。
**评分点:**高级回答会同时比较 p99、内存、错误率和请求字节。
快问 14:连接池是否越大越好?
**推荐回答:**不是。池太小会等待,太大会让更多并发进入 Redis、增加连接和故障重建成本。应根据 QPS、请求耗时、应用实例数和压测结果配置。
**面试官追问:**如何判断池太小?
**常见错误回答:**超时就把 PoolSize 翻十倍。
**评分点:**能使用 WaitCount、WaitDuration、Timeouts 和 Little 定律属于高级。
快问 15:Context、PoolTimeout、ReadTimeout 有什么区别?
**推荐回答:**Context 是业务调用总预算;PoolTimeout 是等待连接的上限;ReadTimeout 是 socket 读取上限。业务 Context 通常不应长于上游剩余超时预算。
**面试官追问:**Context 超时后命令是否一定未执行?
**常见错误回答:**把三者设置成同一个很大的值即可。
**评分点:**高级回答会指出服务器可能继续执行命令。
快问 16:Redis 重试有什么风险?
**推荐回答:**重试能掩盖瞬时网络错误,但可能放大流量、拉长延迟,并使非幂等命令重复执行。必须按错误类型和命令幂等性决定,使用退避、抖动和重试预算。
面试官追问:INCR 超时后能否直接重试?
**常见错误回答:**所有错误都自动重试三次。
**评分点:**高级回答会使用业务幂等 ID 或结果查询。
快问 17:Redis CPU 高时如何排查?
**推荐回答:**先确认业务流量和重试,再看 commandstats 增量、latencystats、SLOWLOG、热 Key、大 Key,随后检查过期、淘汰、Lua、持久化子进程和操作系统 CPU steal。
**面试官追问:**CPU 高但 QPS 下降意味着什么?
**常见错误回答:**第一步就是扩容。
**评分点:**能按因果顺序并区分主线程和子进程属于高级。
快问 18:Redis 内存持续上涨如何排查?
**推荐回答:**先区分数据集增长、管理开销、客户端缓冲、复制/AOF buffer、碎片和 COW;再按命名空间检查 Key 数、TTL 和大 Key,最后检查 RSS 与 Swap。
**面试官追问:**删除大量 Key 后 RSS 为什么不一定下降?
**常见错误回答:**RSS 高就一定是内存泄漏。
**评分点:**高级回答会解释 allocator active、resident 和碎片。
快问 19:used_memory_rss 明显高于 used_memory 一定是问题吗?
**推荐回答:**不一定。可能来自 allocator 碎片、尚未归还操作系统的页面、COW 或其他 RSS 开销。要结合 MEMORY STATS、趋势、负载和 Swap 判断。
**面试官追问:**是否应该看到碎片就立即重启?
**常见错误回答:**两者必须完全相等。
**评分点:**高级回答会评估重启风险、主从切换和主动碎片整理。
快问 20:fork 和 COW 如何影响 Redis?
**推荐回答:**fork 需要复制页表,可能短暂停顿;子进程与父进程共享页面,父进程写入时触发 COW,增加峰值内存和内存带宽压力。数据越大、写入越密集,风险通常越高。
**面试官追问:**如何缓解?
**常见错误回答:**fork 会立刻复制整个 Redis 数据集。
**评分点:**高级回答会提到分片大小、写入模式和持久化测试。
快问 21:Swap 为什么对 Redis 危险?
**推荐回答:**访问被换出的页面需要随机磁盘 I/O,Redis 进程会在页面换入时暂停,造成不可预测的尖峰。应降低内存压力、避免混部并检查 vmstat 和进程 smaps。
**面试官追问:**Swap 使用量非零是否一定正在影响延迟?
**常见错误回答:**Redis 在内存里,因此操作系统不会换出它。
**评分点:**高级回答会关注实时 swap-in/swap-out,而非只看总量。
快问 22:AOF always、everysec、no 如何选择?
**推荐回答:**这是数据安全窗口与延迟、磁盘压力的权衡。always 安全窗口更小但 fsync 成本高;everysec 是常见折中;no 交由操作系统,安全窗口更不可控。应根据 RPO 和磁盘实测选择。
**面试官追问:**AOF 是否等于备份?
**常见错误回答:**AOF always 永远不会丢数据。
**评分点:**高级回答会区分持久化、高可用和离线备份。
快问 23:主从复制延迟如何排查?
**推荐回答:**比较复制 offset 和增长速度,检查链路、断线、全量同步、主副本 CPU/磁盘/Swap、大 Value 和副本查询负载,并验证 backlog 是否能覆盖典型断线窗口。
**面试官追问:**扩大 backlog 能解决所有复制延迟吗?
**常见错误回答:**复制延迟一定是网络问题。
**评分点:**高级回答会区分传输慢、应用慢和频繁全量同步。
快问 24:为什么会频繁故障转移?
**推荐回答:**可能是真宕机,也可能是事件循环被阻塞、fork、Swap、网络丢包或检测超时过紧。必须对齐 Redis、Sentinel/Cluster、客户端和操作系统日志。
**面试官追问:**把故障检测时间调大是否足够?
**常见错误回答:**只要切换成功就说明高可用正常。
**评分点:**高级回答会评估 RTO、RPO、客户端恢复和连接风暴。
快问 25:Redis 容量规划需要考虑哪些内存?
**推荐回答:**数据集、Key 和对象开销、allocator 碎片、客户端缓冲区、复制 backlog、AOF buffer、模块开销、fork/COW 峰值和操作系统余量。
**面试官追问:**为什么不能把 maxmemory 配到物理内存极限?
**常见错误回答:**只用 Key 数乘平均 Value 大小。
**评分点:**高级回答会用真实样本和故障场景计算。
快问 26:Redis 监控应该有哪些 Prometheus 指标?
**推荐回答:**客户端命令量、错误、延迟、重试和池等待;服务端命令 QPS、CPU、内存、RSS、碎片、淘汰和网络;持久化、fork、复制 offset、全量同步和角色切换。
**面试官追问:**能否将完整 Key 作为 label?
**常见错误回答:**只监控 Redis 进程是否存活。
**评分点:**高级回答会讨论 Histogram 和标签基数。
快问 27:OpenTelemetry 对 Redis 排障有什么价值?
**推荐回答:**它把 Redis 调用与 HTTP、RPC、数据库和消息链路关联起来,能观察端到端耗时、错误、重试及上下游关系,帮助判断 Redis 是根因还是受害者。
**面试官追问:**Span 应不应该记录完整 Value?
**常见错误回答:**有 Prometheus 就不需要 Trace。
**评分点:**高级回答会说明指标用于发现、Trace 用于定位、日志用于细节。
快问 28:Redis 安全的基本原则是什么?
**推荐回答:**不暴露公网,只允许可信网络;使用 Redis 6+ ACL 创建命名用户并限制命令和 Key;跨不可信网络启用 TLS;限制 CONFIG、MODULE、DEBUG、FLUSHALL、MONITOR 等高风险命令。
面试官追问:rename-command 是否仍是首选?
**常见错误回答:**设置一个密码就安全了。
**评分点:**高级回答会提到最小权限、证书轮换和审计。
Redis 官方明确不建议将实例直接暴露给不可信网络,并推荐使用 ACL;依靠重命名命令的方式已经被标记为不推荐,应优先采用 ACL 规则。(Redis)
快问 29:go-redis 客户端如何正确复用?
**推荐回答:**一个目标通常复用一个长生命周期客户端,由其管理连接池;每次请求通过 Context 控制超时。redis.Nil 表示 Key 不存在,不等同于连接异常。Pipeline 对象不能跨 goroutine 并发写入。
**面试官追问:**是否应该每次 HTTP 请求创建一个 Client?
**常见错误回答:**为了线程安全,每个 goroutine 创建一个客户端。
**评分点:**高级回答会观测 PoolStats、重试和连接生命周期。
快问 30:什么时候垂直扩容,什么时候水平分片?
**推荐回答:**垂直扩容适合快速缓解资源不足且单实例数据、fork 和恢复时间仍可接受的情况;水平分片适合持续增长、单分片网络或恢复已到边界的情况,但会增加多 Key、事务、Lua、扩缩容和热点 Slot 的复杂度。
**面试官追问:**分片是否能自动解决热 Key?
**常见错误回答:**Redis Cluster 节点越多,所有性能问题都会消失。
**评分点:**高级回答会同时考虑数据模型、N-1、迁移和业务降级。
11. 一分钟面试回答
Redis 性能排查必须先区分端到端延迟和命令执行延迟。一次请求可能包含应用排队、连接池等待、网络、服务器排队、命令执行、响应传输、解码和重试。客户端侧我会监控命令 p99、错误、重试以及连接池 WaitCount、WaitDuration 和 Timeouts;服务端使用 INFO 看 CPU、内存、commandstats、latencystats、持久化和复制,用 SLOWLOG 找具体慢命令,用 LATENCY 看 fork、AOF、过期等内部尖峰,用 MEMORY 和 bigkeys、hotkeys 定位大 Key 与热 Key。CPU 高时先查流量和慢命令,内存高时区分数据集、碎片、缓冲区和 COW,延迟抖动还要排查网络、连接池、Swap 和 fsync。优化上先消除 O(N) 和热点,再减少 RTT、调整连接池与 Pipeline,最后才扩容。容量规划必须包含 COW、碎片、复制和故障余量,压测还应覆盖持久化、故障转移、降级和恢复。安全上使用私有网络、ACL、TLS 和最小权限,不能将 Redis 直接暴露公网。
12. 本章总结
- 性能是端到端系统属性,不能只看 Redis 命令耗时或 QPS。
- SLOWLOG 不是完整调用耗时,它不包含网络、池等待和响应传输。
- INFO、SLOWLOG、LATENCY、MEMORY、客户端 Trace 各自回答不同问题。
- 大 Key 影响操作成本,热 Key 影响流量分布,诊断和治理方式不同。
- Pipeline 和连接池都存在收益递减及反作用,应根据 p99 和错误率选择。
- 客户端超时不代表服务器没有执行命令,重试必须考虑幂等性。
- fork、COW、AOF fsync 和 Swap 是典型的尾延迟来源。
- 扩容之前先修正错误命令、热点、队列和重试模型。
- 容量规划必须在故障、持久化和恢复状态下仍满足 SLO。
- Redis 的安全基础是网络隔离、ACL、TLS 和最小权限,而不是单一密码。
13. 自测清单
13.1 掌握度自测
- 你能否画出一次 Redis 请求的完整端到端延迟组成?
- 你能否解释为什么客户端慢而 SLOWLOG 为空?
- 你能否区分
INFO latencystats与LATENCY LATEST? - 你能否根据两个时间点的 commandstats 找出当前 CPU 热点?
- 你能否解释大 Key、热 Key 和热 Slot 的区别?
- 你能否说明 Pipeline 批次过大的四种风险?
- 你能否说明 Context 超时后写命令为什么仍可能执行成功?
- 你能否按顺序排查复制延迟和频繁故障转移?
- 你能否列出 Redis 峰值内存的主要组成?
- 你能否设计一次包含持久化、故障转移和恢复流量的压测?
13.2 面试前最终检查清单
基础与原理
- 能解释 Redis 为什么快,也能解释为什么会出现尾延迟。
- 不会简单回答“Redis 就是单线程”。
- 熟悉常见命令复杂度及大集合风险。
- 能解释 fork、页表、COW、Swap 和 AOF fsync。
- 能区分持久化、高可用、备份和强一致。
可观测性
- 会使用 INFO 主要分区。
- 会计算累计计数器的窗口增量。
- 会配置和解释 SLOWLOG。
- 会区分 latencystats 与 LATENCY。
- 知道 MONITOR 的风险。
- 会使用 MEMORY STATS、USAGE、bigkeys、memkeys、hotkeys。
- 能设计 Redis Prometheus 指标。
- 能说明 OpenTelemetry Trace 的价值和敏感字段边界。
Go 客户端
- 正确处理
redis.Nil。 - 使用长生命周期共享 Client。
- 能区分 Context、PoolTimeout、ReadTimeout、WriteTimeout。
- 会读取和解释 PoolStats。
- 知道 Pipeline 不可被多个 goroutine 并发使用。
- 能分析超时重试导致的重复执行和重试风暴。
- 会配置 ACL、TLS 和 ClientName。
故障诊断
- 能按顺序排查 CPU 飙高。
- 能区分
used_memory、RSS、碎片和 COW。 - 能排查客户端 p99 抖动但 SLOWLOG 为空。
- 能分析复制 offset、全量同步和 backlog。
- 能分析频繁故障转移是宕机、网络还是阻塞。
- 能设计限流、熔断、退避和重试预算。
架构与运维
- 能进行内存、CPU、网络和连接容量规划。
- 能设计稳态、突发、浸泡和故障压测。
- 能比较垂直扩容和 Cluster 分片。
- 能设计 Redis 故障时的数据库保护策略。
- 能说明 RTO、RPO 和容灾演练结果如何测量。
- 能完成热门缓存、秒杀库存和延迟任务系统设计。
14. 官方资料
本章实际参考的官方资料包括:
- Redis Open Source 版本发布记录。(Redis)
- Redis 官方 Benchmark 指南及常见误区。(Redis)
INFO命令与 commandstats、latencystats 字段。(Redis)- Redis SLOWLOG 文档。(Redis)
- Redis 延迟诊断与延迟监控框架。(Redis)
- Redis
MONITOR命令及性能成本。(Redis) MEMORY USAGE与MEMORY STATS。(Redis)- redis-cli 大 Key、内存和热 Key 分析工具。(Redis)
- Redis 8.6+ 原生 HOTKEYS。(Redis)
- Redis 持久化、RDB 与多文件 AOF。(Redis)
- Redis 官方安全、ACL、TLS 与网络隔离建议。(Redis)
- go-redis 官方仓库、连接池及 OpenTelemetry 集成。(GitHub)
- Prometheus Instrumentation 与 Histogram 指南。(普罗米修斯)
- OpenTelemetry Trace 概念文档。(OpenTelemetry)