千家信息网

Redis中key过期如何解决

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章给大家介绍Redis中key过期如何解决,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。初步调查受影响的团队和缓存团队开始进行初步的调查。我们发现延迟增加与现在正在发生的k
千家信息网最后更新 2026年10月31日Redis中key过期如何解决

这篇文章给大家介绍Redis中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,如果满足过期kry的百分比阈值,则重复此过程直到满足时间限制。

这种扫描所有kry的方法是有效的,当扫描完成时,内存使用量也下降了。似乎Redis不再有效地使key过期了。但是,当时的解决方案是增加集群的大小和更多的硬件,这样key就会分布得更多,就会有更多的可用内存。这是令人失望的,因为前面提到的升级Redis的项目通过提高集群的效率降低了运行这些集群的规模和成本。

Redis版本:有什么改变?

Redis版本2.4和3.2之间,activeExpireCycle的实现发生了变化。在Redis 2.4中,每次运行时都会检查每个数据库,在Redis3.2中,可以检查的数据库数量达到了最大值。版本3.2还引入了检查数据库的快速选项。"Slow"在计时器上运行,"fast" 运行在检查事件循环上的事件之前。快速到期周期将在某些条件下提前返回,并且它还具有较低的超时和退出功能阈值。时间限制也会被更频繁地检查。总共有100行代码被添加到此函数中。


进一步调查

最近我们有时间回过头来重新审视这个内存使用问题。我们想探索为什么会出现regression,然后看看我们如何才能更好地实现key expiration。我们的第一个想法是,在Redis中有很多的key,只采样20是远远不够的。我们想研究的另一件事是Redi 3.2中引入数据库限制的影响。

缩放和处理shard的方式使得在Twitter上运行Redis是独一无二的。我们有包含数百万个key的key空间。这对于Redis用户来说并不常见。shard由key空间表示,因此Redis的每个实例都可以有多个shard。我们Redis的实例有很多key空间。Sharding与Twitter的规模相结合,创建了具有大量key和数据库的密集后端。

过期测试的改进

每个循环上采样的数字由变量

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP

配置。我决定测试三个值,并在其中一个有问题的集群中运行这三个值,然后进行扫描,并测量内存使用前后的差异。如果内存使用前后的差异较大,表明有大量过期数据等待收集。这项测试最初在记忆使用方面有积极的结果。

该测试有一个控件和三个测试实例,可以对更多key进行采样。500和200是任意的。值300是基于统计样本大小的计算器的输出,其中总key数是总体大小。在上面的图表中,即使只看测试实例的初始数量,也可以清楚地看出它们的性能更好。这个与运行扫描的百分比的差异表明,过期key的开销约为25%。

虽然对更多key进行采样有助于我们找到更多过期key,但负延迟效应超出了我们的承受能力。

上图显示了99.9%的延迟(以毫秒为单位)。这表明延迟与采样的key的增加相关。橙色代表值500,绿色代表300,蓝色代表200,控制为黄色。这些线条与上表中的颜色相匹配。

在看到延迟受到样本大小影响后,我想知道是否可以根据有多少key过期来自动调整样本大小。当有更多的key过期时,延迟会受到影响,但是当没有更多的工作要做时,我们会扫描更少的key并更快地执行。

这个想法基本上是可行的,我们可以看到内存使用更低,延迟没有受到影响,一个度量跟踪样本量显示它随着时间的推移在增加和减少。但是,我们没有采用这种解决方案。这种解决方案引入了一些在我们的控件实例中没有出现的延迟峰值。代码也有点复杂,难以解释,也不直观。我们还必须针对每个不理想的群集进行调整,因为我们希望避免增加操作复杂性。


调查版本之间的拟合

我们还想调查Redis版本之间的变化。Redis新版本引入了一个名为CRON_DBS_PER_CALL的变量。这个变量设置了每次运行此cron时要检查的最大数据库数量。为了测试这种变量的影响,我们简单地注释掉了这些行。


//if (dbs_per_call > server.dbnum || timelimit_exit)
dbs_per_call = server.dbnum;

这会比较每次运行时具有限制的,和没有限制的检查所有数据库两个方法之间的效果。我们的基准测试结果十分令人兴奋。但是,我们的测试实例只有一个数据库,从逻辑上讲,这行代码在修改版本和未修改版本之间没有什么区别。变量始终都会被设置。

99.9%的以微秒为单位。未修改的Redis在上面,修改的Redis在下面。

我们开始研究为什么注释掉这一行会产生如此巨大的差异。由于这是一个if语句,我们首先怀疑的是分支预测。我们利用

gcc's__builtin_expect

来改变代码的编译方式。但是,这对性能没有任何影响。

接下来,我们查看生成的程序集,以了解究竟发生了什么。

我们将if语句编译成三个重要指令mov、cmp和jg。Mov将加载一些内存到寄存器中,cmp将比较两个寄存器并根据结果设置另一个寄存器,jg将根据另一个寄存器的值执行条件跳转。跳转到的代码将是if块或else块中的代码。我取出if语句并将编译后的程序集放入Redis中。然后我通过注释不同的行来测试每条指令的效果。我测试了mov指令,看看是否存在加载内存或cpu缓存方面的性能问题,但没有发现区别。我测试了cmp指令也没有发现区别。当我使用包含的jg指令运行测试时,延迟会回升到未修改的级别。在找到这个之后,我测试了它是否只是一个跳转,或者是一个特定的jg指令。我添加了非条件跳转指令jmp,跳转然后跳回到代码运行,期间没有出现性能损失。

我们花了一些时间查看不同的性能指标,并尝试了cpu手册中列出的一些自定义指标。关于为什么一条指令会导致这样的性能问题,我们没有任何结论。当执行跳转时,我们有一些与指令缓存缓冲区和cpu行为相关的想法,但是时间不够了,可能的话,我们会在将来再回到这一点。


解析度

既然我们已经很好地理解了问题的原因,那么我们需要选择一个解决这个问题的方法。我们的决定是进行简单的修改,以便能够在启动选项中配置稳定的样本量。这样,我们就能够在延迟和内存使用之间找到一个很好的平衡点。即使删除if语句引起了如此大幅度的改进,如果我们不能解释清楚其原因,我们也很难做出改变。


关于Redis中key过期如何解决就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

测试 运行 内存 更多 延迟 指令 数据 检查 数据库 版本 代码 影响 之间 实例 性能 时间 问题 变量 大小 样本 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 小米移动互联网科技园 深圳市人人互联网科技有限公司 上海睿民互联网科技有限公司 互联网与科技发展 互联网科技logo设计 互联网科技咨询 互联网科技实习生岗位职责 互联网对科技的发展 广州市恰铎互联网科技有限公司 消费医药和互联网科技 亳州好赞互联网科技有限公司 互联网科技人工智能实验室 浙南科技城互联网大厦建设工程 北京市互联网新科技 黑云互联网科技有限公司 互联网科技年终奖 互联网安防科技感 国产互联网科技公司 高科技和互联网的现代国家 互联网 科技节活动 微视频大赛 喔噻互联网科技有限公司 互联网科技产业 北京互联网科技公司 互联网科技的英文 科技大学互联网专业好不好 深圳市运趣互联网科技有限公司 温州喔噻互联网科技有限公司 长沙茂晟互联网科技有限公司 易企秀互联网科技是做什么的 黑龙江互联网科技公司
0