为什么Redis即使使用maxmemory volatile-lru也会耗尽内存?



几天前我的Redis实例坏了。所有新的写尝试都失败了,并出现这个错误:

OOM command not allowed when used memory > 'maxmemory'

只有在我刷新所有数据后才恢复。它运行在一个有24gb RAM的VPS中,只运行Redis,配置如下:

maxmemory 20gb
maxmemory-policy volatile-lru
save ""

我使用这个实例来存储会话(注意,持久性是禁用的)。每个会话都写入Redis,过期时间为2天,这意味着所有的密钥都有一个TTL:

# Keyspace
db0:keys=1426936,expires=1425758,avg_ttl=87980766

那么为什么它会耗尽内存呢?如果清除策略是volatile-lru,并且所有键都设置了过期时间,那么为什么在达到maxmemory设置时失败,而不是清除键以释放内存呢?

另一件需要考虑的事情是:我的应用程序的负载非常稳定,没有峰值。会话的过期时间为2天。现在它已经运行了六天了,因为我重新启动了实例并刷新了所有,Redis报告了used_memory_human:781.54M。但是,当我检查服务器状态时,我可以看到,在事件发生之前,内存使用一直在缓慢增加。我说的慢是真的慢:它花了将近一年的时间才达到maxmemory=20gb的限制。

但等等!如果会议在两天内到期,这怎么可能呢?事件是否与碎片率有关?我的意思是,会话在两天内到期,并且一直在向Redis写入新的会话。是否有可能在一年内碎片率增长缓慢,导致Redis失败,尽管它已经配置了驱逐策略?

或者有另一种理论情况,Redis不能释放内存足够快?提前感谢!

经过大量的测试和阅读,我得出结论,该事件是由内存碎片引起的。我已经能够解决它打开"活动碎片整理"。

事实证明,在某些情况下,内存碎片是可以预料的。像我这样的场景:一个Redis实例处理数百万个会话,也就是说,很多小的新键不断被写入,也被删除(因为过期)。

我能够验证这一点:事件发生几天后,刷新数据并重启Redis,我看到mem_fragmentation_ratio增长非常缓慢,从1.05上升到2甚至更多!然后我打开activedefrag和mem_fragmentation_ratio开始减少,直到1.05再次。现在已经一个星期了,因为它运行平稳,mem_fragmentation_ratio从来没有超过1.08:)

如果您有疑问,我可以说,打开活动碎片整理的性能成本几乎可以忽略不计。

下面是一些有趣的阅读:https://serverfault.com/questions/971804/are-there-situations-were-activedefrag-should-be-kept-disabled-in-redis-5-with

最新更新