跳到主要内容

Redis 运维与监控

从 INFO 开始​

INFO 是 Redis 自带的体检报告,所有监控指标最终都来自它。不指定段时输出全部,指定段只输出对应部分:

# 全部
redis-cli -h 127.0.0.1 -p 6379 -a "$REDIS_PASS" --no-auth-warning INFO

# 只看某一段
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO clients
redis-cli INFO persistence

输出是 key:value 的纯文本,监控系统抓过来解析即可。下面四段是运维最常看的。

memory​

指标含义怎么看
used_memoryRedis 分配器分配出去的内存总量和 maxmemory 比,超过 80% 就要警惕
used_memory_rss操作系统看到的进程实际占用通常略大于 used_memory,差值就是碎片和开销
used_memory_peak历史峰值判断是否出现过内存尖峰
used_memory_dataset纯数据占用(扣除开销)评估真实数据量
mem_fragmentation_ratiorss / used_memory1.0~1.5 正常,大于 1.5 碎片严重
maxmemory配置的内存上限0 表示不限制,生产必须设
maxmemory_policy淘汰策略确认是 allkeys-lru 还是 noeviction
mem_allocator内存分配器一般是 jemalloc

stats​

指标含义异常信号
total_connections_received累计接受的连接数增长过快说明连接没复用
total_commands_processed累计处理命令数配合时间算 QPS
instantaneous_ops_per_sec当前每秒命令数突增可能是有大量重试或死循环
rejected_connections因 maxclients 被拒的连接数大于 0 就是连接打满
expired_keys累计过期删除的 key 数突增说明有大面积 key 同时到期
evicted_keys累计因内存淘汰的 key 数持续增长说明内存不够
keyspace_hits / keyspace_misses命中 / 未命中次数算缓存命中率
latest_fork_usec最近一次 fork 耗时(微秒)上万就要关注持久化卡顿

缓存命中率直接算:

hit_rate = keyspace_hits / (keyspace_hits + keyspace_misses)

低于 0.8 就该查了:是缓存时间太短、key 设计有问题、还是有大量不存在的 key 被反复查(缓存穿透)。

clients​

指标含义说明
connected_clients当前客户端连接数和连接池上限、maxclients 一起看
blocked_clients阻塞在 BLPOP 等命令上的连接数突然变大可能是队列消费卡住
tracking_clients客户端缓存(client-side caching)连接数没用到就是 0
client_recent_max_input_buffer近期最大输入缓冲异常大说明有超大命令
client_recent_max_output_buffer近期最大输出缓冲异常大说明有慢消费者

persistence​

指标含义正常值
rdb_last_bgsave_status最近一次 RDB 保存结果ok
rdb_last_bgsave_time_sec最近一次保存耗时(秒)越小越好,突增要查
rdb_changes_since_last_save距上次保存的写次数持续增大说明快照没成功
aof_enabled是否开启 AOF按规划确认
aof_last_write_statusAOF 最近写入状态ok
aof_last_bgrewrite_statusAOF 最近重写状态ok
rdb_last_cow_size上次 RDB 期间 COW 复制的字节数越大说明 fork 期间写入越猛
状态字段别只看一眼

rdb_last_bgsave_status:err 和 aof_last_write_status:err 是必须告警的指标——它们意味着持久化已经失败,但 Redis 还在正常接受写请求,看起来一切正常,直到重启才发现数据没了。磁盘满、目录权限错、fork 被 OOM Killer 干掉,都会留下这个状态。

慢查询​

Redis 没有慢查询日志文件,而是把超过阈值的命令记在内存里的一个定长队列中,用 SLOWLOG 查看。

配置​

# 执行时间超过 10000 微秒(10 毫秒)记为慢查询
redis-cli CONFIG SET slowlog-log-slower-than 10000
# 保留最近 256 条
redis-cli CONFIG SET slowlog-max-len 256
# 时间单位是微秒:0 记录所有命令,负数关闭

两个参数都可以在线改,也会被 CONFIG REWRITE 写回配置文件。阈值怎么定?先按「超过 10ms 就记」跑一周,看慢日志里都是什么命令,再决定是放宽阈值还是优化命令。QPS 很高的实例可以设 5ms,低峰实例设 20ms 也没问题。

分析​

redis-cli SLOWLOG GET 10    # 最近 10 条
redis-cli SLOWLOG LEN # 当前条数
redis-cli SLOWLOG RESET # 清空

每条记录长这样:

1) (integer) 14                    # 日志 id
2) (integer) 1716883200 # 发生时间戳
3) (integer) 15321 # 执行耗时,微秒
4) 1) "HGETALL" # 命令及参数
2) "user:1001:profile"
5) "10.0.0.21:42318" # 客户端地址
6) "app-server-1" # 客户端名称(设置了才有)

几个判读要点:

  • 耗时不包含网络传输和排队时间,只是服务端执行命令的时间。所以「应用侧 RT 高但慢日志没记录」很常见,问题在网络上或者客户端到 Redis 的连接排队。
  • HGETALL、SMEMBERS、LRANGE、ZRANGE、KEYS、FLUSHALL、SORT 是慢日志常客,基本都是大 key 惹的祸。
  • DEL 大 key 也慢,它要逐个释放元素。换成 UNLINK 异步删除。
  • Lua 脚本整体算一条,脚本里循环几万次也会以一条记录出现,耗时直接是总时间。

按命令聚合一下,能快速定位是哪个业务在捣乱:

redis-cli SLOWLOG GET 100 | grep -A 1 '^4) 1)' | sort | uniq -c | sort -rn | head

内存治理​

used_memory 与 rss 的差​

used_memory 是分配器视角的「Redis 认为自己用了多少」,used_memory_rss 是操作系统视角的「这个进程实际占了多少物理内存」。两者差值来自三部分:

  • 内存碎片:频繁增删不同大小的对象,分配器找不到合适的空闲块,只能向系统要新页。
  • 分配器预留:jemalloc 按 size class 分配,释放的内存留在池子里复用,不还给系统。
  • 进程自身开销:代码段、栈、连接缓冲区等。
redis-cli INFO memory | grep -E 'used_memory|mem_fragmentation_ratio'

判读规则:

  • ratio 在 1.0~1.5:正常,不用管。
  • ratio 大于 1.5:碎片明显。先看是不是有周期性的大 key 增删,再考虑开自动碎片整理:
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
  • ratio 小于 1:危险信号,说明部分内存被换到 swap 了。Redis 对 swap 极其敏感,一旦换出,延迟会从微秒级跳到毫秒级。立刻检查 vm.swappiness 和机器内存。

大 key 排查​

大 key 没有严格定义,通常指 String 超过 10KB、集合类元素超过 5000 个,或者单个 key 占用内存超过 1MB。它的危害是全方位的:读写阻塞、网络拥塞、删除卡顿、持久化变慢、集群数据倾斜。

# 按类型采样,找出每种类型最大的 key
redis-cli --bigkeys

# 按内存占用找(6.0+,需要扫描,比 --bigkeys 慢)
redis-cli --memkeys

# 精确看某个 key 的内存占用,SAMPLES 0 表示全量采样
redis-cli MEMORY USAGE user:1001:profile SAMPLES 0

--bigkeys 用的是 SCAN 采样,不会阻塞,但结果只是「采样到的最大值」,不保证全局最大。它还会顺带输出每种类型的元素数量分布,可以直接看出哪个类型在膨胀。

治理手段:

  • 拆分:一个大 Hash 按字段哈希拆成多个小 Hash,一个大 List 按时间或用户拆。
  • 异步删除:UNLINK 代替 DEL,把释放内存的动作放到后台线程。配合 lazyfree-lazy-user-del yes、lazyfree-lazy-expire yes、lazyfree-lazy-server-del yes 全局开启。
  • 压缩:JSON 换更紧凑的序列化,或者只存必要字段。
  • 限长:List 用 LTRIM 保留最近 N 条,Set/ZSet 定期清理冷数据。
大 key 要在设计阶段拦

上线后才发现大 key,迁移和拆分都很痛。code review 时盯住「往集合里无界追加」的写法,比如用户行为流水直接 RPUSH 不设上限、订单商品明细整个塞一个 Hash。加一个「单 key 元素上限」的约定,比事后治理便宜得多。

接入 Prometheus​

手工敲 INFO 只能应急,长期监控要把指标采起来。Redis 本身不暴露 Prometheus 格式,中间需要一个 exporter。

redis_exporter 是最常用的一个,单二进制、无状态,直接容器跑:

docker run -d --name redis_exporter \
-p 9121:9121 \
oliver006/redis_exporter:v1.58.0 \
--redis.addr=redis://10.0.0.11:6379 \
--redis.password='Your_Strong_Password_Here'

确认能抓到指标:

curl -s http://127.0.0.1:9121/metrics | grep '^redis_up'
# redis_up 1

然后在 Prometheus 的 scrape_configs 里加一个 job:

scrape_configs:
- job_name: redis
scrape_interval: 15s
static_configs:
- targets:
- 10.0.0.11:9121
labels:
instance: redis-master
env: prod

重启或热加载 Prometheus,在 UI 里查 redis_up 能看到 1 就通了。常用指标:

指标对应 INFO用途
redis_up进程存活实例是否可达,最基础的告警
redis_memory_used_bytesused_memory内存水位
redis_memory_max_bytesmaxmemory算内存使用率
redis_connected_clientsconnected_clients连接数水位
redis_commands_processed_totaltotal_commands_processed算 QPS
redis_keyspace_hits_totalkeyspace_hits算命中率
redis_keyspace_misses_totalkeyspace_misses算命中率
redis_evicted_keys_totalevicted_keys是否有淘汰发生
redis_rejected_connections_totalrejected_connections连接是否被打满
redis_slowlog_lengthSLOWLOG LEN慢查询堆积情况

几条能直接用的告警规则:

groups:
- name: redis
rules:
- alert: RedisDown
expr: redis_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Redis 实例不可达"

- alert: RedisMemoryHigh
expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Redis 内存使用率超过 85%"

- alert: RedisEvicting
expr: rate(redis_evicted_keys_total[5m]) > 0
for: 10m
labels:
severity: warning
annotations:
summary: "Redis 正在持续淘汰 key,缓存容量不足"

指标含义、拉模型和 PromQL 的基础,见 Prometheus 核心概念与架构。Grafana 上用现成的 Redis Dashboard(社区有几个常用模板),导入后把数据源指向 Prometheus 即可。

注意 redis_memory_max_bytes 为 0(没设 maxmemory)时,内存水位的除法告警不会触发,这类实例要单独加一条基于 redis_memory_used_bytes 和机器内存的规则。

日常巡检清单​

每天扫一眼,比出事再查便宜得多:

# 内存水位、碎片率、淘汰次数
redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli INFO stats | grep -E 'evicted_keys|rejected_connections|expired_keys'

# 连接数与阻塞数
redis-cli INFO clients

# 持久化状态
redis-cli INFO persistence | grep -E 'rdb_last_bgsave_status|aof_last_write_status|rdb_last_bgsave_time_sec'

# 复制状态(有从库时)
redis-cli INFO replication | grep -E 'role|connected_slaves|lag'

# 慢查询 Top
redis-cli SLOWLOG GET 5

小结​

  • INFO 四段:memory 看水位和碎片,stats 看命中率/淘汰/拒绝连接,clients 看连接数,persistence 看 RDB/AOF 是否成功。
  • 慢查询靠 slowlog-log-slower-than 记录,SLOWLOG GET 分析;10ms 起步,重点盯 HGETALL、KEYS、大 DEL。
  • 内存治理先分清 used_memory 和 rss,碎片超 1.5 考虑 activedefrag,大 key 用 --bigkeys/--memkeys 找、用 UNLINK 删、从设计上拆分。
  • 监控接入用 redis_exporter 暴露指标,Prometheus 抓取后配 redis_up、内存水位、淘汰速率三条基础告警。
  • 巡检常态化:内存、连接、持久化状态、复制延迟、慢查询,五项每天过一遍。

指标都正常还出问题,那就是故障排查的范畴了,下一篇把 OOM、fork 卡顿、连接打满、主从延迟这些高频故障逐个拆开,见《故障排查与最佳实践》。