跳至正文
来两杯美式
返回

Redis 知识系列(二):高效使用

By 来两杯美式
发布于

常用命令速查

info                     # 查看详情
info memory              # 查看内存
info replication         # 查看主从状态
info stats               # 查看命令统计
info keyspace            # 查看各 db 的 key 数量和命中数
object idle time <key>   # 查看 key 的闲置时间(秒)

INFO 关键字段详解

关键字段用途
Serverredis_versionuptime_in_seconds版本与运行时长
Clientsconnected_clientsblocked_clients当前连接数、被阻塞的客户端数
Memoryused_memoryused_memory_peakmem_fragmentation_ratio已用内存、历史峰值、内存碎片率(>1.5 需要排查)
Statstotal_commands_processedinstantaneous_ops_per_secrejected_connections总命令数、QPS、被拒连接
Replicationroleconnected_slavesmaster_repl_offset主从状态
Keyspacedb0:keys=10000,expires=200,avg_ttl=60000各 db 的 key 数、过期数、平均 TTL

实战经验:


事务与 Lua

MULTI/EXEC 事务

MULTI          # 开启事务
SET k1 v1      # 返回 QUEUED
INCR k2        # 返回 QUEUED
EXEC           # 顺序执行,返回每条命令的结果

事务的 4 个特性:

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 缓存脚本避免每次传输脚本内容。


批量操作

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 × 平均命令执行时间) × 冗余系数

举例:

关键指标:业务峰值 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       # 清空队列

返回示例:

慢查询日志条目样例

每条日志字段含义:

  1. 日志唯一标识符 uid。
  2. 命令执行时的系统时间戳
  3. 命令执行的时长(微秒)。
  4. 命令和命令的参数。

实战:定位”Redis 突然变慢”

排查思路(按优先级):

  1. 看 INFO Statsinstantaneous_ops_per_sec 是否异常飙升?rejected_connections 是否增长?
  2. 看 INFO Clientsblocked_clients 是否很多?说明有 BLPOP/XREAD 等阻塞。
  3. 查 slowlog get:定位具体慢命令,是 KEYS *?还是大 key 的 HGETALL
  4. 看 INFO Memorymem_fragmentation_ratio 飙升?内存碎片严重。
  5. 看 INFO CPUused_cpu_sysused_cpu_user 是否异常。
  6. 看持久化阻塞:AOF everysec 配置下,如果磁盘 IO 抖动,主线程会阻塞等 fsync。
  7. 看 fork 阻塞:RDB/AOF 重写时的 fork 会阻塞主进程(页表复制),大内存机器尤其明显。

经验值:单机 Redis 内存不要超过 6-8 GB,否则 fork 阻塞会非常明显。超过 10 GB 建议用物理机或专用节点。


命令文档

redisdoc.com


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
Redis
第 2 / 4 篇
查看系列全部文章
  1. 01.Redis 知识系列(一):数据结构与单机原理
  2. 02.Redis 知识系列(二):高效使用
  3. 03.Redis 知识系列(三):持久化与高可用
  4. 04.Redis 知识系列(四):集群与缓存架构

上一篇
MySQL 知识系列(五):隔离级别、Spring 事务与查询流程
下一篇
MySQL 知识系列(四):日志系统:redo log、undo log、binlog