常用命令速查
info # 查看详情
info memory # 查看内存
info replication # 查看主从状态
info stats # 查看命令统计
info keyspace # 查看各 db 的 key 数量和命中数
object idle time <key> # 查看 key 的闲置时间(秒)
INFO 关键字段详解
| 段 | 关键字段 | 用途 |
|---|---|---|
| Server | redis_version、uptime_in_seconds | 版本与运行时长 |
| Clients | connected_clients、blocked_clients | 当前连接数、被阻塞的客户端数 |
| Memory | used_memory、used_memory_peak、mem_fragmentation_ratio | 已用内存、历史峰值、内存碎片率(>1.5 需要排查) |
| Stats | total_commands_processed、instantaneous_ops_per_sec、rejected_connections | 总命令数、QPS、被拒连接 |
| Replication | role、connected_slaves、master_repl_offset | 主从状态 |
| Keyspace | db0:keys=10000,expires=200,avg_ttl=60000 | 各 db 的 key 数、过期数、平均 TTL |
实战经验:
used_memory_rss / used_memory远大于 1.5 说明内存碎片严重,考虑重启或开启activedefrag yes(4.0+)。instantaneous_ops_per_sec持续低于历史水位说明可能存在热点或阻塞。rejected_connections增长说明客户端连接池满或 maxclients 不足。
事务与 Lua
MULTI/EXEC 事务
MULTI # 开启事务
SET k1 v1 # 返回 QUEUED
INCR k2 # 返回 QUEUED
EXEC # 顺序执行,返回每条命令的结果
事务的 4 个特性:
- 使用
MULTI开始事务,批量操作在发送EXEC命令前被放入队列缓存。 EXEC后顺序执行,任意命令执行失败,其余命令依然被执行(Redis 事务不回滚)。- 事务执行过程中,其他客户端提交的请求不会插入到事务执行序列中。
- Redis 事务不支持原子性的完整语义(无回滚),更准确的叫法是”打包执行”。
Lua 脚本(原子执行)
复杂的业务场景需要”读-判断-写”原子完成时(事务做不到),用 Lua:
-- 库存扣减的 Lua 脚本
local stock = tonumber(redis.call('GET', KEYS[1]))
if not stock or stock <= 0 then
return 0
end
redis.call('DECR', KEYS[1])
return 1
调用:
EVAL "脚本内容" 1 stock:item:1001
为什么不用事务:因为事务中间没办法根据中间结果决定是否继续执行。Lua 在 Redis 里作为一个整体命令执行(单线程模型 + 整个脚本原子),天然支持条件分支。
事务 vs Lua 对比
| 场景 | 选事务 | 选 Lua |
|---|---|---|
| 简单的多条独立写 | ✅ | ❌ |
| 需要根据中间结果分支判断 | ❌ | ✅ |
| 需要循环处理多个 key | ❌ | ✅ |
| 跨多个 key 的 CAS | ❌ | ✅ |
| 想保持逻辑可读 | ✅(简单场景) | ✅(复杂场景) |
实战经验:Lua 脚本不要写得太长(建议 < 100 行),否则会长时间阻塞 Redis 单线程。可以通过
EVALSHA缓存脚本避免每次传输脚本内容。
批量操作
- string 类型使用
mget/mset,hash 类型使用hmget/hmset等。 - 批量操作将多次网络往返时间缩减为一次。
- 时间复杂度 O(n),由于 Redis 单线程特性,应合理安排批量 key 的个数(单批建议 ≤ 500),以免造成阻塞。
Pipeline 管道
Redis 基于请求-响应模型,单个请求需要”一问一答”。Pipeline 批量执行指令,客户端把多个命令打包一起发,服务端顺序处理后一次性返回,节省多次 IO 往返时间。
# redis-cli 方式
printf "PING\nSET k1 v1\nGET k1\n" | redis-cli -p 6379
Pipeline vs 事务:Pipeline 只是”打包传输”,不是原子执行,服务端可能插入其他客户端的命令。事务(MULTI/EXEC)则是原子顺序执行。如果需要原子性,两者可以组合使用(MULTI + 多条命令 + EXEC 仍走 Pipeline 路径)。
异步队列
普通队列
RPUSH queue:messages "msg1" # 生产消息
LPOP queue:messages # 消费消息(非阻塞)
BLPOP queue:messages 10 # 阻塞消费(10 秒超时)
BLPOP 在队列空时会阻塞直到有消息或超时,避免在代码中用 sleep 轮询。
pub/sub 主题模式
subscribe topic # 订阅频道
publish topic "msg" # 向 topic 频道发送消息
重要缺陷:消息发布是无状态的,发送完消息无法保证消息被接收到。如果消费者在生产者发送过程中下线,再上线是接收不到消息的。
Stream(5.0+ 推荐)
要解决 pub/sub 的丢消息问题:
XADD queue:stream * field1 value1 # 生产消息
XREAD BLOCK 0 COUNT 10 STREAMS queue:stream 0 # 消费消息
XREADGROUP GROUP g1 c1 BLOCK 0 COUNT 10 STREAMS queue:stream > # 消费者组消费
Stream 提供 pub/sub 没有的:消息持久化、消费者组、消息回溯。生产中推荐用 Stream 或专业消息队列(Kafka/RocketMQ),只在实时通知且允许丢失的场景用 pub/sub。
连接池设置合适的 maxTotal
连接池过大浪费资源(Redis 服务端最大连接数有限,一般 1w),连接池过小可能成为瓶颈。
计算公式
连接池数 = (QPS × 平均命令执行时间) × 冗余系数
举例:
- 命令平均执行时间 0.1ms = 0.0001s
- 业务需要 50000 QPS
- 理论需要 50000 × 0.0001 = 5 个连接
- 实际应配置的略大一些(考虑网络抖动等),比如 10-20 个
关键指标:业务峰值 QPS、Redis
instantaneous_ops_per_sec、客户端连接池等待时间。三者结合动态调整 maxTotal。
慢查询实战
慢查询配置
# 默认值
slowlog-log-slower-than = 10000 # 超过 10ms 记为慢查询(微秒)
slowlog-max-len = 128 # 队列最大长度
# 动态配置(推荐生产用动态配置)
config set slowlog-max-len 10000
config set slowlog-log-slower-than 1000 # 可配 0,记录所有命令用于分析
慢查询日志操作
slowlog get [n] # 获取最近 n 条慢查询
slowlog len # 获取队列长度
slowlog reset # 清空队列
返回示例:

每条日志字段含义:
- 日志唯一标识符 uid。
- 命令执行时的系统时间戳。
- 命令执行的时长(微秒)。
- 命令和命令的参数。
实战:定位”Redis 突然变慢”
排查思路(按优先级):
- 看 INFO Stats:
instantaneous_ops_per_sec是否异常飙升?rejected_connections是否增长? - 看 INFO Clients:
blocked_clients是否很多?说明有BLPOP/XREAD等阻塞。 - 查 slowlog get:定位具体慢命令,是
KEYS *?还是大 key 的HGETALL? - 看 INFO Memory:
mem_fragmentation_ratio飙升?内存碎片严重。 - 看 INFO CPU:
used_cpu_sys和used_cpu_user是否异常。 - 看持久化阻塞:AOF
everysec配置下,如果磁盘 IO 抖动,主线程会阻塞等 fsync。 - 看 fork 阻塞:RDB/AOF 重写时的 fork 会阻塞主进程(页表复制),大内存机器尤其明显。
经验值:单机 Redis 内存不要超过 6-8 GB,否则 fork 阻塞会非常明显。超过 10 GB 建议用物理机或专用节点。