本文是大数据系列第 44 篇,介绍 Redis 慢查询日志的工作原理与配置方法,以及一套可落地的生产性能调优策略。
慢查询日志概述
Redis 提供类似 MySQL 慢查询日志的机制,记录执行时间超过阈值的命令,帮助定位性能瓶颈。
内部实现
Redis 使用一个固定长度的 FIFO 队列存储慢查询记录:
- 超出容量时自动淘汰最旧记录
- 查询时间复杂度为 O(1)
- 只记录命令执行时间,不包含网络传输和排队等待时间
配置参数
slowlog-log-slower-than
设置记录阈值,单位为微秒(1 秒 = 1,000,000 微秒)。
| 值 | 行为 |
|---|---|
> 0 | 记录执行时间超过该值的命令 |
0 | 记录所有命令(调试用) |
< 0 | 不记录任何命令(关闭慢日志) |
默认值:10,000 微秒(10ms) 生产建议:1,000–10,000 微秒(1–10ms),根据业务 SLA 调整
# 动态修改(立即生效,重启失效)
CONFIG SET slowlog-log-slower-than 5000
# 写入配置文件(永久生效)
# slowlog-log-slower-than 5000
slowlog-max-len
设置慢日志队列最大条数。
默认值:128 生产建议:1,000–10,000(视内存允许适当调大)
CONFIG SET slowlog-max-len 1000
核心命令
# 获取最近 N 条慢查询记录(默认 10 条)
SLOWLOG GET [n]
# 查看当前慢日志条数
SLOWLOG LEN
# 清空所有慢日志
SLOWLOG RESET
SLOWLOG GET 返回格式(每条记录包含):
- 唯一 ID
- 命令执行的 Unix 时间戳
- 执行耗时(微秒)
- 命令及参数列表
性能优化策略
数据结构层
| 问题 | 解决方案 |
|---|---|
| Key 命名冗长 | 使用简洁、有意义的 Key 名称 |
| String 存大整数 | 改用 Integer 类型(内存更小) |
KEYS * 全量扫描 | 改用 SCAN 游标迭代 |
HGETALL 读大 Hash | 改用 HMGET 指定字段或 HSCAN 分批读取 |
| 大 Value(>10KB) | 拆分为多个小 Key 或压缩后存储 |
命令层
Pipeline:将多条命令打包为一次网络请求,减少 RTT(Round-Trip Time):
// Jedis Pipeline 示例
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 1000; i++) {
pipeline.set("key:" + i, "value:" + i);
}
pipeline.sync();
批量命令:优先使用 MSET/MGET、HMSET/HMGET 而非多次单条命令。
配置层
- 开启 AOF 时,
appendfsync everysec比always性能更好 - 设置
maxmemory防止内存耗尽触发 swap,拖慢所有命令 - 大数据集避免频繁
BGSAVE,可调大save触发间隔
MONITOR 命令
实时查看 Redis 接收的所有命令(含时间戳和客户端信息):
MONITOR
警告:MONITOR 会对 Redis 吞吐量产生显著影响(最高降低 50%),仅限临时调试,禁止在生产环境长期运行。
监控体系建议
生产环境推荐使用以下监控栈:
Redis 实例 → redis_exporter → Prometheus → Grafana
核心监控指标
| 指标 | 说明 |
|---|---|
used_memory | 内存使用量,接近 maxmemory 时告警 |
instantaneous_ops_per_sec | 每秒命令数,反映负载 |
connected_clients | 连接数,异常增长可能是连接泄漏 |
keyspace_hits/misses | 缓存命中率 |
rdb_last_bgsave_status | RDB 持久化状态 |
aof_current_size | AOF 文件大小,过大时触发重写 |
master_link_status | 主从复制健康状态 |
测试环境快速配置
# 记录所有命令,只保留最近 2 条(用于功能测试)
CONFIG SET slowlog-log-slower-than 0
CONFIG SET slowlog-max-len 2
# 执行一些命令后查看
SET foo bar
GET foo
SLOWLOG GET
通过慢查询日志 + 监控体系的组合,可以系统性地发现并解决 Redis 性能问题,而不是依赖经验猜测。