BodySense Redis 第 11 课:Operations 与 Observability
学习 Redis INFO、SLOWLOG、MEMORY、LATENCY、SCAN 与关键运行指标,并把 BodySense 的认证状态、连接池、持久化和缓存观测收敛成可运维的健康模型。
[!info] related notes
- 课程 MOC:BodySense Redis 从零到一课程 MOC
- 前置课程:第 10 课
- 对应知识笔记:Redis 运维、观测与故障语义、Redis
- BodySense:BodySense 可观测性设计
BodySense Redis 第 11 课:Operations 与 Observability
[!abstract] 学习目标 从“会用 Redis 命令”提升到“知道 Redis 在生产中现在是否健康、哪里慢、是否正在丢状态”。
先从零解释:Operations、Monitoring、Observability 分别是什么
这一课不再主要问“Redis 命令怎么写”,而是问:
系统已经跑在生产里了,我怎么知道它现在健康不健康、哪里开始变慢、故障到底发生在哪一层?
Operations / 运维
广义上是让 Redis 在真实环境中持续可用:
配置
部署
容量
升级
备份/恢复
故障处理
安全
监控
Monitoring / 监控
监控更像:
提前选好一组指标,然后持续观察这些指标是否越过阈值。
例如:
used_memory > 80%
evicted_keys increases
connected_clients > threshold
Redis command p99 > 20ms
Observability / 可观测性
可观测性更强调:
当你事先不知道故障是什么时,系统是否提供足够的内部信号,让你从外部行为反推出内部状态。
常见信号:
Metrics
Logs
Traces
Profiles / runtime introspection
Redis 自身提供 INFO / SLOWLOG / LATENCY / MEMORY / CLIENT 等 introspection;应用侧还要记录 Redis operation latency、error classification、request trace。
所以:
Redis PING = OK
只是一个非常窄的信号,绝不能代表“生产 Redis 健康”。
先学一个排障原则:从用户症状向下收集证据
假设:
Login API p95
100 ms → 2 s
不要第一步就:
重启 Redis
而应该逐层问:
1. HTTP request 到底慢在哪个 span?
2. Redis operation 本身慢,还是在等 client pool?
3. Redis server 是否有 slow command / latency spike?
4. memory / eviction / persistence 是否异常?
5. network / DNS / TLS 是否异常?
这个思路叫 evidence-driven diagnosis:先区分假设,再修复。
基础诊断命令
INFO
CLIENT LIST
SLOWLOG
MEMORY
LATENCY
SCAN
DBSIZE
每个命令回答的问题不同。
INFO:Redis Server 的“体检总表”
INFO 返回 Redis Server 的运行信息和统计。
可以直接:
INFO
也可以只看某一类:
INFO memory
INFO clients
INFO persistence
INFO stats
INFO replication
INFO keyspace
INFO commandstats
INFO latencystats
当前官方文档还包含 errorstats、keysizes、hotkeys 等 section;不同版本/发行形态可能有差异,因此生产排查先确认实际 Redis 版本。
为什么不要一上来 INFO all 然后盯着一大屏数字
因为指标必须对应一个问题。
例如“登录延迟变高”:
clients
→ 是否连接数量/拒绝连接异常?
memory
→ 是否接近上限、RSS/fragmentation 异常?
commandstats / latencystats
→ 哪类命令 CPU/latency 上升?
persistence
→ AOF rewrite / fork 是否发生?
只有带着假设看指标,数字才有意义。
关键指标
used_memory
Redis 自己统计的分配内存。
used_memory_rss
操作系统层面 Redis 进程实际 RSS。
两者差距很大时,需要考虑:
- allocator;
- fragmentation;
- fork / copy-on-write;
- 操作系统内存行为。
connected_clients
当前客户端连接。
突然升高可能意味着:
- connection leak;
- pool 配置异常;
- 流量增长;
- retry storm。
rejected_connections
连接因资源限制被拒绝。
增长时属于明显可用性信号。
blocked_clients
存在阻塞等待的客户端。
需要结合使用的 blocking command / workload 判断。
expired_keys
业务 TTL 到期
通常可以正常增长。
evicted_keys
Redis 因 memory policy 淘汰 Key
对于 BodySense 当前承载认证 authority 的实例:
长期关键 invariant:evicted_keys 应保持 0。
keyspace_hits / keyspace_misses
对于 Cache 可以推导 hit ratio。
但对 Session authority:
miss
可能表示正常过期、Logout、无效 Token,而不是“缓存性能差”。
指标含义必须结合 Key 类型。
instantaneous_ops_per_sec
观察当前命令吞吐。
不能只用它评价健康,还要同时看:
- latency;
- CPU;
- network;
- error rate。
SLOWLOG:记录“Redis 自己执行得慢”的命令
SLOWLOG 是 Redis 内置的慢命令日志。
最重要的边界:
Slow Log 统计的是 Redis 执行命令所花的时间,不包含客户端网络 I/O。
所以:
Application sees 500ms
SLOWLOG sees 1ms
可能意味着:
network
client pool wait
TLS
application scheduling
连接建立
而不是 Redis command CPU 本身慢。
查看:
SLOWLOG GET 20
SLOWLOG LEN
Redis 通过配置阈值决定多慢才进入 slowlog,并限制保存条数。
什么命令容易慢
不应只背某几个命令,而要看两个因素:
command algorithmic complexity
+
这个 Key / collection 到底有多大
例如:
对一个 5-member Set 做 SMEMBERS
→ 很轻
对一个几百万成员的大 Set 做全量操作
→ 可能很重
Lua 同理:脚本本身是原子执行,如果内部做巨大循环,就会把其他请求一起挡住。
因此排障时要把:
SLOWLOG
+ Big Key
+ command complexity
一起看。
MEMORY:到底是“数据多”,还是内存组织出了问题
常用:
MEMORY STATS
MEMORY USAGE some:key
MEMORY DOCTOR
used_memory 与 used_memory_rss
used_memory 可以粗略理解为 Redis allocator 认为当前分配给 Redis 数据结构等的内存。
used_memory_rss 是操作系统视角下 Redis 进程实际驻留的物理内存。
如果:
RSS >> used_memory
可能涉及 allocator fragmentation、历史峰值后未返还给 OS、fork/copy-on-write 等。
如果:
used_memory >> RSS
官方文档提示可能有一部分 Redis 内存被操作系统 swap 出去,这通常会带来显著延迟风险。
为什么删除很多 Key 后 RSS 不一定马上下降
Redis 释放对象后,内存先还给 allocator;allocator 不一定立刻把 page 还给操作系统。
所以:
used_memory ↓
RSS 仍然高
不自动等于“Redis memory leak”。
需要结合:
used_memory_peak
allocator fragmentation
实际 key count
长时间趋势
判断。
Big Key 是什么
Big Key 不是只有“Value 超过某个固定 MB”才算。
它更像:
一个 Key 的大小/成员数已经让单次读取、遍历、删除、复制、迁移或持久化形成明显延迟/资源风险。
例如:
一个 String 50 MB
一个 Set 300 万 members
一个 Hash 200 万 fields
风险形态不同,但都可能是 Big Key。
Hot Key 又是什么
Hot Key 不是“大”,而是访问特别集中。
key 很小
但每秒 100k 次 GET
也可能成为 CPU/network/shard 单点热点。
因此:
Big Key = size / operation cost 问题
Hot Key = traffic concentration 问题
两者可能重合,也可能完全不同。
LATENCY:观察 Redis Server 内部出现过哪些延迟尖峰
Redis 有 Latency Monitoring Framework。
例如:
LATENCY LATEST
可以看到最近记录的 latency event、发生时间、最近延迟和实例启动以来的最大值。
它和 SLOWLOG 不是一回事:
SLOWLOG
→ 具体哪条 command 执行时间超过阈值
LATENCY
→ Redis 内部某类 latency event / spike
潜在来源可能包括:
slow command
fork
persistence
CPU scheduling
storage
memory pressure
所以“某条 API 慢”不能只看一个工具,要把 server latency event 与应用 trace 对齐时间。
SCAN vs KEYS:遍历 Keyspace 也有执行模型
KEYS pattern 的危险不是“这个命令被官方讨厌”,而是它尝试一次性遍历匹配整个 keyspace。
当数据很多时:
KEYS *
→ 长时间占用命令执行路径
→ 其他请求等待
Redis 官方延迟排障文档明确建议生产环境避免把 KEYS 当常规遍历工具。
SCAN 是 cursor-based incremental iteration
开始:
SCAN 0 MATCH 'session:*' COUNT 100
Redis 返回:
next cursor
+
这一批 keys
下一轮:
SCAN <next-cursor> MATCH 'session:*' COUNT 100
直到 cursor 再次返回 0,完成一次 full iteration。
COUNT 是 Hint,不是严格 page size
COUNT 100
不保证“每次一定返回 100 个”。Redis 官方文档明确把它定义成工作量提示;一次可能返回更少、更多,甚至 0 个。
SCAN 也不是 Snapshot
遍历期间 keyspace 可能在变化。
官方语义允许:
- 某些元素重复返回;
- 在遍历期间忽隐忽现的元素结果不确定。
所以应用使用 SCAN 时要能处理重复,并且不要把它当作一致性快照查询。
为什么它仍不应该成为业务查询方式
假设需求:
找 user 42 的所有 Session。
错误思路:
SCAN all session:*
→ GET each
→ parse user
→ filter user 42
正确建模更像:
user_sessions:42
→ direct Set index
SCAN 是运维/维护遍历工具,不是“Redis 没 SQL,所以业务查询就全库扫”。
MONITOR 的风险
MONITOR 可以看到服务器执行的大量命令,对排查非常直观。
但生产常驻风险包括:
- 性能开销;
- 巨量输出;
- 可能暴露敏感命令参数。
因此:
不把 MONITOR 当长期 observability 方案。
Client Policy:Redis Server 健康,Client 也可能把自己拖死
应用并不是“每次命令都临时建 TCP 连接”。Redis 客户端通常维护连接池/复用连接。
因此客户端本身也有容量与失败策略:
Dial / Connect timeout
Read timeout
Write timeout
Pool size
Pool wait timeout
Idle connections
Retries
Reconnect / backoff
TLS
Timeout 为什么必须是有界的
Auth Redis 如果慢 30 秒,而 HTTP request 也一直等 30 秒:
request goroutines pile up
connections stay occupied
upstream retries
more traffic
→ cascading failure
所以安全关键依赖不是“等得越久越可靠”。
目标是:
在一个明确时间预算内
成功获得可信结果
或者
明确失败并执行 failure policy
Retry 为什么可能把故障放大
假设 Redis 已经过载:
1000 failed requests
× each retry 5 times
= up to 5000 extra attempts
这叫 retry amplification / retry storm。
好的 retry 通常需要:
bounded attempt count
backoff
jitter
only retry transient errors
respect request deadline
operation retry must be safe/idempotent
后面第 12 课会把它放进 Failure Engineering。
BodySense 当前代码要区分“现在是什么”和“未来该补什么”
当前 apps/api/internal/database/redis.go 显式设置的是:
Addr
Password
DB
optional TLS
startup PING
它目前没有在这里显式配置完整的 Dial/Read/Write timeout、PoolSize、MaxRetries 等策略。
所以课程列出这些参数时,含义是:
生产审计应该显式评估这些 client policy;不是声称当前 BodySense 已经全部配置完成。
Redis Health 不等于 PING
PING → PONG
只证明最基础连接可用。
生产健康还包括:
latency
memory headroom
eviction
persistence status
connection pool
command errors
replication/failover
hot key / big key
BodySense 推荐观测
Auth
session lookup latency
session lookup error
refresh rotation success/error
refresh replay detected
rate-limit decision
Redis auth dependency unavailable
Cache
hit
miss
fill latency
fallback count
invalidation
stampede suppression
Notification
publish error
subscribe reconnect
fallback reconciliation count
Prediction
[!question]
- expired_keys 很高是否一定是故障?
- evicted_keys 在 BodySense Auth Redis 增长意味着什么?
- 为什么 Cache miss rate 和 Session miss rate 不能用同一语义解读?
- 为什么 SCAN 不应该替代业务 secondary index?
- PING 正常但 p95 Redis latency 已经极高,能否说 Redis “健康”?
[!success]- Answer / 解析 1. expired_keys 很高是否一定是故障?
不一定。大量验证码、Session、Rate Limit counter 正常 TTL 到期,本来就会推动 expired_keys 增长。要结合业务创建速率、TTL 分布和异常变化趋势判断。2. evicted_keys 在 BodySense Auth Redis 增长意味着什么?
表示 Redis 正因内存压力提前淘汰 Key。若其中包含 Session / Refresh / security rate-limit 状态,就可能造成提前掉登录、授权状态丢失或安全窗口重置,因此对 critical Auth Redis 是高优先级告警。3. Cache miss rate 与 Session miss rate 为什么不能同义解释?
Cache miss 主要描述缓存命中效率;Session miss 可能是正常 Logout、TTL 到期、无效 Token 或撤销结果,是认证业务语义。把 Session miss 当“缓存命中率差”会得出错误优化方向。4. 为什么 SCAN 不应该替代业务 secondary index?
SCAN 是渐进遍历 Keyspace 的运维工具,不提供针对业务查询的稳定数据模型。每次为了“找某用户的 Session”去遍历整个 Keyspace,复杂度和延迟都随总 Key 数增长;更合理的是维护 user_sessions:这样的专用索引。 5. PING 正常但 p95 Redis latency 很高,Redis 能算健康吗?
不能。PING 只证明基础连接和最简单命令还能返回。生产健康还包括业务命令延迟、pool 等待、memory headroom、eviction、slowlog、persistence、network 等。如果用户请求已经受到明显延迟影响,系统就不是健康状态。
Lab
redis-cli INFO
redis-cli SLOWLOG GET
redis-cli MEMORY STATS
redis-cli LATENCY LATEST
redis-cli SCAN 0 MATCH 'session:*' COUNT 100
同时从 BodySense 侧记录:
request latency
Redis operation latency
error classification
user-visible HTTP result
把“Redis 内部指标”与“用户请求结果”关联起来。
L4 Gate
给出一次事故:
登录 API p95 突然从 100ms → 2s
Redis PING still OK
能够提出有顺序的证据收集:
application error/latency
→ Redis op latency
→ pool saturation
→ slowlog/latency
→ memory/eviction
→ persistence/fork
→ network
而不是直接“重启 Redis”。