最近我们在Redis集群中发现了一个有趣的问题。在花费大量时间进行调试和测试后,通过更改key过期,我们可以将某些集群中的Redis内存使用量减少25%。
Twitter内部运行着多个缓存服务。其中一个是由Redis实现的。我们的Redis集群中存储了一些Twitter重要的用例数据,例如展示和参与度数据、广告支出计数和直接消息。
问题背景
早在2016年初,Twitter的Cache团队就对Redis集群的架构进行了大量更新。Redis发生了一些变化,其中包括从Redis 2.4版到3.2版的更新。在此更新后,出现了几个问题,例如用户开始看到内存使用与他们的预期或准备使用的内存不一致、延迟增加和key清除问题。key的清除是一个很大的问题,这可能导致本应持久化的数据可能被删除了,或者请求发送到数据原始存储。
初步调查
受影响的团队和缓存团队开始进行初步的调查。我们发现延迟增加与现在正在发生的key清除有关。当Redis收到写入请求但没有内存来保存写入时,它将停止正在执行的操作,清除key然后保存新key。但是,我们仍然需要找出导致这些新清除的内存使用量增加的原因。
我们怀疑内存中充满了过期但尚未删除的key。有人建议使用扫描,扫描的方法会读取所有的key,并且让过期的key被删除。
在Redis中,key有两种过期方式,主动过期和被动过期。扫描将触发key的被动过期,当读取key时, TTL将会被检查,如果TTL已过期,TTL会被删除并且不返回任何内容。Redis文档中描述了版本3.2中的key的主动过期。key的主动过期以一个名为activeExpireCycle的函数开始。它以每秒运行几次的频率,运行在一个称为cron的内部计时器上。activeExpireCycle函数的作用是遍历每个密钥空间,检查具有TTL集的随机kry,如