Redis刚接入业务时,通常效果很明显。原来直接查数据库的接口,加一层缓存后响应变快了;一些频繁读取的数据放进Redis后,数据库压力也降下来了。
时间一长,Redis里存的东西越来越多,用法也越来越复杂。最开始只是缓存商品信息、用户状态、验证码,后来又开始放配置、排行榜、任务状态、限流计数,甚至临时队列。业务越跑越久,问题也会慢慢积累。
Redis的麻烦之处在于,它平时看起来很安静。CPU不高,内存还有余量,监控曲线也没明显波动。可一到活动、发布、批处理任务或者流量上涨时,隐藏的问题就会被放大。接口突然慢了,应用开始报超时,数据库压力跟着升高,排查时才发现Redis里早就埋了不少隐患。
大Key:平时不明显,操作时容易卡
大Key是Redis里很常见的问题。
比如一个List里塞了几十万条记录,一个Hash里放了大量字段,一个String存了几MB的数据。平时只读一小部分内容时,可能感觉不到异常。但只要碰到批量读取、删除、迁移、备份或者主从同步,大Key就容易拖慢整个实例。
之前见过一个业务场景,用户行为记录一直往同一个List里写。刚开始数据量小,接口表现正常。后来数据越积越多,一次版本发布后,程序新增了批量读取逻辑,相关接口开始频繁超时。服务器资源并没有明显打满,Redis也没有宕机,最后查出来是这个List太大,读取时耗时明显增加。
大Key最麻烦的地方,是它不一定每天都出问题。它可能在某个特殊操作里突然暴露出来,比如删除一个很大的Key,或者从节点重新同步数据。这个时候,业务侧看到的就是短时间卡顿、延迟升高,甚至请求失败。
治理大Key的思路很朴素:不要把所有数据都塞进一个Key里。集合类数据要控制大小,必要时按用户、时间、业务类型拆分。读取时也不要一次取完,能分页就分页,能分批就分批。对已经存在的大Key,要先摸清楚来源,再安排低峰期处理,避免直接在线上粗暴删除。
热Key:一个点太热,也会影响整体
热Key不一定很大,但访问特别频繁。
比如首页配置、热门商品、活动开关、排行榜、库存信息、登录态校验,这些数据可能很小,但每秒都有大量请求访问。如果所有请求都打到同一个Key,Redis处理压力就会集中在一个点上。
热Key在平时不容易发现,访问量不高时一切正常。等到活动开始、消息推送发出、用户集中访问时,问题就会出来。业务侧会感觉接口变慢,但查数据库发现压力不一定高,因为压力主要集中在Redis这一层。
处理热Key,要结合业务特点。变化不频繁的数据,可以放一层本地缓存,减少每次都访问Redis。访问量特别高的Key,可以拆成多个副本,让请求分散读取。对于活动类场景,还要提前压测,看看高峰时Redis的响应时间是否稳定。
热Key的核心不是“Redis能不能扛住”,而是不要让所有请求都挤在同一个点上。
缓存同时失效,会把压力推给数据库
Redis最常见的用法是缓存。缓存命中时,系统很快;缓存失效后,请求会回到数据库。
如果大量Key设置了相同的过期时间,它们可能在同一时间一起失效。原本由Redis承担的访问压力,会突然落到数据库上。数据库连接数升高,查询变慢,应用线程被占住,用户看到的就是页面卡、接口慢、请求超时。
还有一种情况是某个热点Key刚好过期,大量请求同时发现缓存没有数据,于是一起去查数据库。一个热点Key就可能把后端服务打得很吃力。
解决这类问题,不需要复杂设计,关键是提前处理好回源逻辑。缓存过期时间可以加一点随机值,避免同一时间集中失效。热点数据可以提前刷新。查数据库时可以加互斥控制,让少量请求去回源,其余请求等待或读取旧数据。对于不存在的数据,也可以短时间缓存空结果,避免反复查询。
缓存好用,但不能只写“没有就查数据库”。高并发下,这句话背后可能藏着很大的风险。
内存没满,也不代表Redis健康
很多人看Redis状态,第一眼会看内存使用率。内存没满,就觉得问题不大。
实际排查时,内存要看得更细。Key数量有没有持续增长,是否存在大量没有过期时间的临时数据,内存碎片率是否偏高,淘汰策略是否符合业务要求,这些都很重要。
有些业务把Redis当临时存储用,但写入时忘了设置过期时间。刚开始看不出问题,几个月后Key越来越多,内存慢慢涨上来。等接近上限时,Redis开始按照淘汰策略清理数据,业务可能会出现缓存突然丢失、命中率下降、接口变慢等情况。
还有一种问题是内存碎片。频繁写入、删除、更新后,Redis占用的系统内存可能比实际数据内存高不少。表面看还有空间,实际可用情况已经不理想。
所以Redis内存巡检不能只看“用了多少”。还要看增长趋势、碎片率、淘汰次数、过期Key数量和不同业务的数据占比。趋势比某一时刻的数值更有参考价值。
慢命令会让后面的请求排队
Redis执行命令很快,但并不代表所有命令都适合在线上随便用。
keys *、大范围hgetall、一次性读取大List、大集合遍历、大对象删除,这些操作在数据量小时没什么感觉,数据量上来后就容易拖慢Redis。一个慢命令执行时间长了,后面的请求就要排队等待。
线上环境尤其要谨慎使用keys *。它看起来方便,但在实例里Key很多时,会造成明显阻塞。更合适的方式是使用scan分批扫描,并控制每次处理数量。
建议打开Redis慢日志,并定期看一下。慢日志能帮助定位哪些命令耗时长、来自哪个客户端、集中在哪些业务模块。很多时候,Redis变慢不是机器配置问题,而是某些使用方式不适合线上环境。
客户端连接也会出问题
Redis服务端看起来正常,不代表客户端访问正常。
有些应用连接池配置过小,高峰期拿不到连接,请求就会排队。也有些应用连接池配置过大,大量服务一起连上来,Redis连接数被撑高。还有些程序频繁创建短连接,用完就断,带来额外开销。
批处理任务也需要注意。一个定时任务如果瞬间发起大量Redis请求,可能影响正常业务接口。再加上客户端重试策略不合理,短暂超时可能被放大成持续压力。
排查Redis超时问题时,除了看服务端CPU、内存、慢日志,也要看应用侧连接池、超时时间、重试次数和调用频率。Redis运行正常,应用依然超时,这种情况并不少见。
备份和恢复要提前验证
不少系统把Redis当缓存使用,觉得数据丢了也能重新加载。但实际业务里,Redis经常存着一些状态类数据,比如登录状态、限流计数、任务进度、队列信息。如果这些数据突然丢失,业务影响可能并不小。
因此,Redis的持久化和备份不能只停留在“有配置”。RDB或AOF策略是否合适,AOF文件是否过大,主从同步是否稳定,故障切换后应用是否能正常连接,这些都要提前验证。
备份文件存在,不代表恢复就能成功。恢复后的数据是否完整,实例能否正常启动,业务能否识别这些数据,都需要演练。平时不演练,真到故障时再验证,风险会很高。
Redis巡检要放到日常工作里
Redis治理不适合等故障后再做。更稳妥的方式,是把巡检放进日常运维里。
每隔一段时间检查大Key、热Key、慢日志、内存增长、连接数、主从延迟和备份恢复情况。业务活动前、系统发布前、节假日前,最好再做一次重点检查。这样可以在问题影响用户之前,先把风险处理掉。
Redis问题通常不是某一天突然发生的,而是长期使用过程中慢慢堆出来的。早一点发现,处理成本很低;等到线上接口已经超时,再去查大Key、扫慢日志、改连接池,就会被动很多。
运维服务的价值,体现在持续治理上
在企业环境里,Redis通常和应用、数据库、云主机、网络、备份、监控系统连在一起。Redis慢了,可能影响接口;接口超时,可能拖住应用线程;应用重试,又可能把数据库压力拉高。一个小问题,很容易沿着调用链扩散。
这也是为什么Redis治理不能只靠一次优化。它需要持续巡检、监控告警、容量评估、备份验证、变更记录和应急预案。对运维人员不足、系统数量较多的企业来说,外部运维服务可以补上一部分长期保障能力。
据我了解,江苏立维运维服务在企业基础设施、数据库运维、云运维和7×24保障方面有一些实际项目经验。像Redis这类长期运行、问题容易累积的组件,可以结合日常巡检、监控优化、备份恢复验证和故障响应一起管理。
Redis本身很稳定,但稳定运行不等于可以长期不管。大Key、热Key、慢命令、内存碎片、连接堆积、备份不可用,这些问题越早发现,处理越简单。
等到业务已经变慢,再去补这些基础工作,往往就晚了一步。