Redis 性能
Redis 的内存访问、事件循环、Pipeline 与延迟排查。
一次请求花了多少时间
Redis 请求延迟包括获取连接、编码与发送、服务端排队和执行、响应传输及解码。命令执行快,客户端也可能等得久。以普通 TCP 连接上的小值 GET 为例:
请求延迟 ≈ 客户端准备时间 + 请求传输时间 + 服务端排队时间
+ 命令执行时间 + 响应传输与解码时间小值 GET 执行时间短,网络往返和队列等待往往占去更多时间。返回大量数据时,命令执行、编码和传输的成本都会增加。
吞吐量是单位时间内完成的请求数,延迟分位数反映请求等待时间的分布。增加并发可以提高吞吐量,也可能拉长队列,推高尾延迟。压测时要一起看这两类指标。
内存访问与命令开销
Redis 的普通数据访问在内存中完成,GET 无需为每次查询读取磁盘页。执行时仍要计算哈希、比较键、访问对象并复制数据,长键和大值会增加这些开销。
数据库缓冲池也能让查询命中内存。Redis 的另一项特点是命令操作范围明确,可以直接按键、字段或区间取数据。
GET demo:name
HGET demo:user:42 name
LRANGE demo:events 0 99
ZRANGE demo:ranking 0 19 WITHSCORES这些命令分别读取字符串、哈希字段、列表片段和有序集合的有限区间。只取所需范围,可以减少服务端处理、响应编码和客户端解析的工作。
同一数据类型会随 Redis 版本、元素数量和大小采用不同的内部编码,可用 OBJECT ENCODING 查看。工作集较大时,CPU 缓存局部性和分配器行为也会影响访问速度。
事件驱动与命令串行化
Redis 使用 I/O 多路复用处理连接就绪事件,无需为每个空闲连接维持独立的阻塞线程。事件循环在连接可读或可写时推进相关操作,从而降低大量连接等待时的线程管理与切换成本。
在 Redis 7.2 的常见配置下,普通命令主要由主线程依次执行。该安排减少了命令并行修改共享数据所需的协调,但也使长时间执行的命令阻塞后续请求。低复杂度 GET 若排在慢命令之后,执行时间仍然较短,端到端延迟却可能明显上升。
Redis 7.2 还可以配置网络 I/O 线程,后台释放和持久化也会用到其他线程或进程。它们与前台请求争用 CPU、内存带宽和磁盘资源,但普通命令仍主要在主线程上依次执行。
增加连接数能送入更多请求。命令执行资源饱和后,这些请求会排队,慢命令、大 key 操作和突发流量都可能拉长等待时间。
批量通信与响应规模
对于互不依赖的请求,逐条发送并等待回复会重复承担串行往返等待。Pipeline 允许连续发送一批命令,再按顺序接收响应。它减少等待和部分通信开销,不减少命令本身的执行次数,也不提供整批原子性。
两组压测保持连接数和请求总量一致,将 Pipeline 深度从 1 改为 16:
# Redis 7.2 自带 redis-benchmark;仅在测试实例执行
redis-benchmark -h 127.0.0.1 -p 6379 -t get -n 10000 -c 1 -P 1
redis-benchmark -h 127.0.0.1 -p 6379 -t get -n 10000 -c 1 -P 16比较 Pipeline 的效果时,保持键值大小、命中情况、客户端位置、TLS、持久化和其他负载一致,记录吞吐量及延迟分位数。
Pipeline 会积累请求和响应,批次过大会增加缓冲占用和批次内等待。限制批次时既要看命令条数,也要看预计响应大小;大值查询还会消耗带宽和解码资源。后一条命令依赖前一条结果时,仍需等待。
延迟排查
客户端耗时覆盖完整访问过程,慢日志主要记录命令执行时间。客户端慢而慢日志没有记录时,可以检查连接池等待、网络、服务端排队和响应大小。
SLOWLOG GET 10
INFO commandstats
INFO memory| 主要现象 | 对应开销 | 分析重点 |
|---|---|---|
| 单条命令执行耗时较高 | 命令执行 | 命令类型、集合规模、读取范围 |
| 命令执行较短,客户端耗时较高 | 准备、排队或通信 | 连接池等待、服务端负载、网络及响应大小 |
| 小请求吞吐受往返限制 | 通信等待 | 受控批次下的 Pipeline 对照 |
| 后台任务期间延迟升高 | 资源竞争 | CPU、内存、交换与持久化活动 |