在 Redis 的实际部署中,如果 Redis 突然变慢就会直接影响到用户的使用体验,增加了请求的延迟,特别是使用Redis 作为秒杀系统中的缓存的时候,由于长时间不能响应用户的请求,会失去大量的用户,然而为了解决 Redis 突然变慢的现象不能盲目求医,在 16,17 节中我们将结果要提升 Redis 的性能可以从 Redis 的异步线程机制和绑核操作两个方面下手。
一、Redis 真的变慢了嘛?
- 在判断 Redis 是否真的变慢的直接的方式就是去查看其响应延迟的时间,但是由于软硬件不同,判断 Redis 变慢的响应延迟标准也不会相同,然而还有另一个方法用于判断 Redis 是否真的变慢了,也即是基于当前环境下啊Redis “基线性能”来判断。(基线性能也就是在当前的配置,在无压力,无干扰的情况下的基本性能,这个性能只能由当前的软硬件配置决定)
- 如果你不了解基线性能,一看到较高的运行时延迟,就很有可能误判 Redis 变慢了。由于基线性能只与当前的软硬件配置相关,因此我们将 Redis 运行时延迟与基线性能的延迟行对比,如果发现运行时延迟基线性能的两倍有余,那么基本就可以判断 Redis 变慢了。
二、如何应对 Redis 变慢了?
使得 Redis 变慢的需要结合 Redis 交互的操作系统,存储的文件系统,以及网络等外部的系统方面去进行分析问题,其中使得 Redis 变慢的主要原因分为三个主要部分:Redis 自身的特性,操作系统和文件系统,如下图所示,接下来就会以这三个方面着手来进行 Redis 变慢问题的定位。
(1)Redis 自身操作特性的影响
- 当 Redis 性能变慢时,根据执行操作的时间复杂度来判断是否属于慢查询。当有大量的慢查询需要执行的时候有两种解决方案
- 当需要对含有大量数据的集合进行全量获取的时候可以选择采用 SCAN 命令来代替,渐进式的返回一定的数据,避免一次性返回全部大量的数据导致阻塞主线程,最终造成 Redis 的性能变差。
- 当需要执行排序,交集,并集操作时候可以选择在客户端下完成,以免拖慢 Redis 实例。
- 如果当必须在 Redis 实例中执行这些命令,那就可以选择采用 CPU 性能更好的环境下执行。
- 除了上面提及的慢查询操作以外,还有 KEYS 操作,因为 KEYS 命令是根据输入的 key 进行模糊匹配,因此当执行这个操作的时候就需要对 Redis 实例中的所有键值对进行遍历,同样也属于一种慢查询的操作,所以对于 KEYS 操作不建议在生产环境下使用。
(2)过去 key 的清除操作
在 Redis 中有两种算法来执行清除 Redis 中过期的 key 的自动清除操作,它是用于 Redis 自身的回收内存空间的机制,当被执行应用的广泛的时候就会造成对 Redis 在性能上的影响。Redis 中的 key 可以设置过期时间,默认情况下,Redis 每 100ms 就会对过期的 key 进行清除操作。
- 设置 Redis 的配置参数 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP,该参数表示每次 Redis 定时进行过期 key 的清除操作的时候默认删除多少个过期的 key 的个数(默认是 20),当设置为 20 时,每 100ms 进行清除操作,那么 1s 内就需要进行 10 次清除操作,每次设置清除 20 个过期的 key,那么 1s 内基本上就会对 200 个过期的 key 被清除了。这个样的操作对 Redis 的性能影响比较小。
- 还有第二种算法,当 Redis 中过期的 key 的个数大于等于全部 key 的 25% 的时候,那么 Redis 就会一直执行清除过期 key 的操作,直至过期的 key 的含量小于 25%,在执行清除过期 key 操作期间,Redis 无法正常的响应其他的请求操作,进而给 Redis 造成阻塞的影响。因此当触发到这个算法的时候就很容阻塞主线程,但是在 Redis 4.0 之后就采用了异步线程机制,创建新的线程来负责删除键值对的操作,因而避免了对 Redis 主线程带来的阻塞。
因此当出现 Redis 变慢的情况下,可以选择去检查业务代码中设置的 key 是不是使用了相同的时间参数,导致大量的 key 在同一时间内需要 Redis 进行清除操作,进而导致 Redis 被阻塞,使得后面的请求延迟增加了。当确实有一批 key 设置了相同的过去时间参数,那么我们可以在其时间上加上一定范围的随机数,使得这些 key 在临近的时间被清除,避免了同一时刻过期 key 清除操作的压力。