当前位置:首页 > 问答 > 正文

Redis用久了内存总得清理下,不然性能慢慢就掉了,别忘了优化啊

“Redis用久了内存总得清理下,不然性能慢慢就掉了,别忘了优化啊”这个说法,其实点出了很多使用Redis的人在实际运维中会遇到的一个非常现实的问题,它不像服务器突然宕机那样是个急性病,更像是一种慢性损耗,一开始感觉不明显,但时间长了,各种小毛病就都来了。(来源:常见的运维经验总结)

为啥会这样呢?你得先知道Redis的一个核心特点:它主要是靠把数据放在内存里来达到那种飞快的读写速度的,内存这东西,比硬盘贵,空间也有限,你不停地往Redis里写数据,比如缓存用户会话、存储热门商品信息、记录排行榜等,数据量只会越来越大,虽然Redis本身有一些被动的清理机制,但很多时候它不会像你想象的那样“自动”把没用的数据立刻扔掉。(来源:Redis基于内存存储的特性)

这就好比是你家的储藏室,刚搬进去的时候,空空荡荡,找什么东西都特别快,住了几年后,东西越堆越多,有些东西明明已经用不到了,比如旧杂志、坏掉的电器,但你一直没抽空去清理,结果就是,每次想找一件当下急需的东西,都得在杂物堆里翻腾半天,效率自然就低了,Redis也是同理,内存被大量不再访问的数据占着,当有新数据需要写入时,Redis可能就需要先花时间去寻找并清理掉一些旧数据来腾地方,这个寻找和清理的过程本身就会消耗CPU资源,并且可能引起短暂的延迟波动。(来源:内存碎片和过期键清理的类比)

具体有哪些“杂物”需要我们留意并清理呢?主要有这么几类:

第一类是“明文规定”了过期时间,但还没来得及被清理的数据,Redis给数据设置过期时间(TTL)是非常常见的做法,比如短信验证码缓存10分钟,Redis有两种主要的过期键删除策略:一种是惰性删除,就是当客户端尝试访问一个键时,才发现它已经过期了,然后顺手把它删掉;另一种是定期删除,Redis会每隔一段时间随机检查一些键,淘汰掉其中过期的,问题在于,惰性删除太被动,如果某个过期键一直没人访问,它就会一直占着坑,定期删除呢,如果过期键太多,而Redis配置的检查力度不够,也可能清理不干净,结果就是,你的Redis实例里可能存在着大量的“僵尸键”,它们已经失效了,但还占据着宝贵的内存空间。(来源:Redis过期键的删除策略)

第二类是从来没设置过期时间,但实际上已经成了“冷数据”,某个促销活动早就结束了,但当时缓存的活动页面数据还一直留在Redis里;或者某些用户已经很久没登录了,但他们的部分缓存信息还在,这些数据可能再也不会被访问到,成了内存中的“钉子户”。(来源:对冷数据的常见描述)

第三类是由于频繁修改和删除导致的内存碎片,想象一下,你不断地往Redis里写入一些大小不一的数据,然后又删除掉其中一部分,内存中就会留下许多小的、不连续的空闲空间,虽然这些空间总和很大,但如果现在要存入一个稍微大一点的数据,可能都找不到一块完整的、足够大的连续空间来存放它,这就好比停车场上停满了车,开走几辆后,空出了几个车位,但都是分散的,这时候来了一辆加长林肯,它就停不进去,Redis为了应对这种情况,需要启动内存碎片整理过程,把分散的小空闲空间“挤一挤”,合并成大的连续空间,这个过程(特别是在版本较低时)是阻塞性的,可能会引起服务短暂停顿,而且整理本身也耗资源。(来源:Redis内存碎片化原理)

“优化”具体要做些什么呢?肯定不是让你动不动就重启Redis,那样太粗暴了,而且会丢失所有数据(如果没开持久化的话)。

你得养成定期“巡检”的习惯,用Redis自带的命令,比如INFO memory,看看当前内存使用了多少,有多少键已经过期但还没被清除,内存碎片率是多少,这就像定期给Redis做个体检,做到心中有数。(来源:Redis监控命令)

针对过期键问题,你可以适当调整Redis的配置,可以加强定期删除的力度(调整hz参数),让Redis更频繁地检查过期键,这会在一定程度上增加CPU负担,需要在时间和空间之间做个权衡。(来源:Redis配置参数优化建议)

对于大量的冷数据,最有效的办法可能就是主动清理了,你可以写个脚本,定期扫描(使用SCAN命令,千万别用会阻塞服务的KEYS命令)那些没有设置过期时间的键,然后根据你的业务逻辑判断哪些是可能已经失效的冷数据,比如最后访问时间远早于当前时间的,然后安全地删除它们,这就像定期对储藏室进行一次大扫除,把积灰的、用不上的东西果断扔掉。

对于内存碎片,新版本的Redis提供了主动碎片整理的功能(ACTIVE DEFRAGMENTATION),你可以配置它在碎片率超过一定阈值时自动在后台运行,虽然可能对性能有轻微影响,但能避免碎片问题积累到不得不重启的地步,这就好比平时偶尔花点时间整理下储物柜,总比等到乱得下不去脚再彻底收拾要省力得多。

还有一个治本的方法,就是从写入Redis的时候就开始注意,给数据设置合理的过期时间,避免无休止地增长,评估一下哪些数据真的有必要缓存,不要什么都往Redis里扔,这就像养成“断舍离”的习惯,买东西的时候就想好以后怎么处理,从源头上减少杂物的产生。

“Redis用久了需要清理和优化”这个提醒非常中肯,它不是一个一次性的任务,而应该成为一个持续的、基于监控的运维习惯,放任不管,性能的 degradation(下降)是必然的,虽然缓慢,但影响是真切存在的,定期花点小功夫做下维护,就能让Redis一直保持“年轻态”,稳定高效地为你服务。(来源:对持续优化理念的总结)

Redis用久了内存总得清理下,不然性能慢慢就掉了,别忘了优化啊