Redis 延迟波动问题

本文将介绍 Redis 中的响应延迟波动问题,并介绍其检测方法和解决方案。

一、延迟波动问题

在 Redis 实际应用中,有一个非常严重的问题,那就是 Redis 突然变慢了。

一旦出现这个问题,不仅会直接影响用户的使用体验,同样还会影响系统中的其它组件。

二、问题检测

1. 查看响应延迟

可以通过查看 Redis 响应延迟的绝对值判断其是否变慢。

2. 延迟波动判断

由于不同的软硬件环境下,Redis 的性能不同,因此延迟波动需要结合过往情况进行判断。

一般而言,我们可以在 Redis 工作正常时测试基线性能,将其作为判断依据。

所谓的基线性能,就是一个系统在低压力、无干扰的情况下的基本性能,可以作为 Redis 在某个环境下响应延迟的指标。

从 Redis 2.8.7 开始,Redis 提供了 -intrinsic-latency 选项用于检测和统计测试期间的最大延迟,可以将这个延迟作为 Redis 的基线性能。一般而言,我们将测试期设为 120 秒,Redis 将统计每 120 秒的最大延迟。

1
2
3
4
5
6
7
8
9
./redis-cli --intrinsic-latency 120
Max latency so far: 17 microseconds.
Max latency so far: 44 microseconds.
Max latency so far: 94 microseconds.
Max latency so far: 110 microseconds.
Max latency so far: 119 microseconds.

36481658 total runs (avg latency: 3.2893 microseconds / 3289.32 nanoseconds per run).
Worst run took 36x longer than the average latency.

3. 网络波动判断

延迟波动可能还与网络状态有关,可以通过 iPerf 之类的工具测试 Redis 客户端至服务端的延迟,判断网络状态是否正常。

三、原因

1. 慢查询

所谓慢查询命令,就是在 Redis 中执行速度慢的命令,这会导致 Redis 延迟增加。

常见的慢查询命令有:

  • 复杂度高的命令

  • KEYS 命令

    KEYS 命令需要遍历存储的键值对,所以操作延时较高

处理方法是:

  • 换用高效命令:比如需要遍历集合的成员时,不一次性获取,而是使用 SCAN 命令多次迭代返回
  • 当需要执行排序、交集、并集操作时,在应用服务器中完成,将 Redis 作为单纯的存取数据库
  • 避免在生产环境使用 KEYS 命令

2. key 过期

Redis 支持为键值对设置过期时间,并且会自动删除它们,删除机制为:

  • 每 100 毫秒扫描 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 个过期的 key,删除它们
  • 如果有超过 25% 的 key 过期,重复执行删除,直至降低比例

其中,第一个机制并不会对 Redis 造成太大影响,而如果触发第二个机制,Redis 将会堵塞式删除键值对,进而影响其它操作。

因此,应该避免大量的 key 同时过期,具体做法是:给不同的 key 设置不同的过期时间;即使过期时间实在必须相近,也应该在过期时间基础上加一定的随机数。

3. 文件系统

(1) 说明

Redis 会持久化保存数据到磁盘,这个过程要依赖文件系统完成,因此文件系统将数据写回磁盘的机制会影响 Redis 持久化的效率,持久化的效率高低又会影响到 Redis 处理请求的性能。

(2) AOF 持久化

当持久化方式设置为 AOF 时,有两个堵塞点:

  • 如果写回策略设为 always,Redis 不会用子线程异步 fsync,而是堵塞等待 fsync

  • Redis 会自动进行 AOF 重写,这个过程会对磁盘进行大量 IO 操作,当 AOF 重写压力较大时,将会导致 fsync 被堵塞。

    此时,

    • 假如写回策略为 always,则主线程将被堵塞

    • 假如写回策略为 no 或 ererysec,虽然 Redis 会异步 fsync 执行,但主线程也会监控 fsync 的执行进度,如果主线程在执行新命令时发现上一次的 fsync 还没有执行完,则主线程也会被堵塞

      如果对延迟比较敏感,且允许一定的数据丢失,可以将配置项 no-appendfsync-on-rewrite 设置为 yes,这样在进行 AOF 重写时将不会进行 fsync 操作

4. 操作系统

(1) 说明

Redis 是内存数据库,因此操作系统的内存机制会直接影响到 Redis 的处理效率。

(2) 内存 swap

内存 swap 是操作系统中将内存数据在内存和磁盘间来回换入和换出的机制。当内存空间不足时,操作系统便可能触发 swap,将数据在内存和磁盘之间 “倒腾”,以维持一个 “更大的内存空间”。

作为内存数据库,一旦操作系统触发 swap,Redis 操作需要等待磁盘读写,其响应时间将会极大增加。

(3) 内存大页

内存大页机制也是一种可能影响 Redis 性能的机制。常规的内存页分配以 4KB 为单位,从 Linux 内核 2.6.38 开始,内存大页机制支持内存页以 2MB 为单位分配。

内存大页机制有许多好处,比如分配相同大小的内存可以减少分配次数;但是内存大页机制也会带来坏处,Redis 持久化时会进行写时复制,当启用内存大页机制时,数据被修改拷贝内存需要拷贝更多的空间,这将影响 Redis 的性能。

在实际生产环境中部署时,不建议开启内存大页机制,可以执行命令如下:

1
echo never /sys/kernel/mm/transparent_hugepage/enabled

参考