文章目录引言如何判断Redis是否真的变慢方法一观察响应延迟的绝对值方法二基于基线性能做判断Redis自身操作特性的影响慢查询命令过期key的集中删除诊断思路总结引言Redis突然变慢是生产环境中最棘手的问题之一。它不仅直接影响用户体验还会在业务系统中引发连锁反应——Redis延迟增加会拖慢上游事务导致数据库连接池耗尽进而让整个服务链路雪崩。面对这类问题最忌讳的就是病急乱投医。本文将介绍一套系统性的诊断方法先确认Redis是否真的变慢再从Redis自身操作特性入手排查根因。如何判断Redis是否真的变慢方法一观察响应延迟的绝对值最直接的判断方式是看Redis命令的执行时间。如果响应延迟突然从微秒级跳到毫秒甚至秒级出现所谓的延迟毛刺基本可以认定Redis变慢了。但这种方法有局限性不同软硬件环境下Redis的正常延迟水平不同。在高配物理机上0.2ms可能就算慢了而在虚拟机上1ms可能还在正常范围内。方法二基于基线性能做判断更科学的方法是测量当前环境下Redis的基线性能——即低压力、无干扰下的基本性能表现由当前软硬件配置决定。从Redis 2.8.7版本开始redis-cli提供了--intrinsic-latency选项来测量基线性能redis-cli --intrinsic-latency120这个命令会在120秒内监测并输出最大延迟值。例如输出结果为119微秒那么基线性能就是119微秒。判断标准如果运行时延迟达到基线性能的2倍及以上就可以认定Redis变慢了。这个方法对虚拟化环境尤其重要。虚拟机或容器本身会引入额外的性能开销基线性能可能高达几毫秒。如果不了解基线看到较高的运行时延迟就容易误判。注意--intrinsic-latency需要在Redis服务器端直接运行以排除网络因素的干扰。如果需要评估网络影响可以用iPerf等工具单独测量客户端到服务器的网络延迟。Redis自身操作特性的影响确认Redis变慢后首先从Redis自身的操作特性入手排查。重点关注两类问题慢查询命令和过期key操作。慢查询命令Redis命令的执行速度与其算法复杂度直接相关操作类型示例命令复杂度String读写GET/SETO(1)Set排序SORTO(NM*log(M))Set聚合SUNION/SMEMBERSO(N)全局遍历KEYSO(N)当N元素个数很大时这些命令的执行时间会显著增加阻塞Redis主线程。排查方法通过Redis慢查询日志或latency monitor工具查找执行时间异常的命令对照官方文档确认其复杂度。解决方案用高效命令替代例如用SSCAN替代SMEMBERS分批迭代返回数据避免一次性返回大量结果阻塞线程。将聚合计算移到客户端SORT、SUNION、SINTER等操作可以在客户端完成不要让Redis承担计算密集型工作。禁止在生产环境使用KEYS命令KEYS需要遍历所有键值对操作延迟极高。替代方案是使用SCAN命令通过游标分批遍历SCAN0COUNT100SCAN每次返回一批key和下一个游标值循环调用直到游标返回0即完成全量遍历。虽然可能返回重复key发生在哈希表缩容时但不会漏key。过期key的集中删除Redis的过期key删除机制是一个容易被忽视的性能杀手。删除机制Redis每100毫秒执行一次过期扫描随机采样ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP个key默认20个删除其中已过期的如果过期key比例超过25%重复步骤1直到比例降到25%以下正常情况下每秒删除约200个过期key影响不大。但如果触发了第二条规则——大量key在同一时刻过期——Redis会持续执行删除操作这个删除是阻塞的Redis 4.0后可用异步线程缓解主线程无法处理其他请求。触发条件使用EXPIREAT命令为大批key设置了相同的UNIX时间戳或者用EXPIRE给批量key设置了相同的过期秒数。解决方案在过期时间上加一个随机偏移量把集中过期打散# 不好的做法所有key在同一时刻过期redis.expireat(key,fixed_timestamp)# 好的做法加随机偏移在一个时间窗口内分散过期importrandom jitterrandom.randint(0,300)# 0-300秒的随机偏移redis.expireat(key,fixed_timestampjitter)这样既保证了key在一个邻近时间范围内被清理又避免了同一秒内大量key集中过期导致的阻塞。诊断思路总结Redis性能诊断需要从三个维度系统性排查Redis自身操作特性本文重点慢查询命令、过期key集中删除文件系统AOF持久化机制对磁盘IO的依赖操作系统swap机制、内存大页等排查时要有章法逐一检查而不是凭直觉猜测。先确认问题是否存在基线性能对比再按照影响因素逐层排查。下篇将继续从文件系统和操作系统层面介绍更多导致Redis变慢的原因及其解决方案。