缓存过期的最佳算法

3
我需要一个简单的缓存结构(用Python实现,但实际上并不重要),有一些特定的要求:
  1. 多达数百万个小对象(平均每个100字节)
  2. 速度至关重要(放置和获取),我希望操作时间在几微秒左右
  3. 只有一个线程访问此数据 - 因此可以全部保存在内存中(无需持久化)
  4. 密钥是MD5哈希(如果有影响)
  5. 有一个全局的过期时间,每个密钥应在过期时间后从缓存中删除,计算从第一次放置开始的时间
现在问题是如何实现过期 - 因为其他所有内容都可以使用简单的字典来完成。最简单的解决方案是定期迭代所有数据并删除过期的密钥 - 但这可能会锁定整个缓存太长时间。通过在每个清理过程中迭代部分数据来改进它 - 但仍需要一些时间(或者不能足够快地清除)。逐个删除密钥看起来像浪费CPU - 因为它们可以批量删除(不必在过期后立即删除 - 我们可以为保留已过期的密钥一段时间而承受一些额外的RAM)。
检索期间检查密钥是不够的(尽管仍应该这样做,以避免返回过期密钥) - 因为许多密钥可能永远不会被检索,然后它们将永远存在(或者存在时间太长)。
大多数解决此问题的答案建议使用memcached,但我认为这将浪费CPU,特别是因为我保存可以通过引用放置到字典中的对象,但是使用memcached时它们必须进行(反)序列化。
我有一些关于如何实现这个想法:将数据分成时间片,实际上有几个字典 - 例如,如果过期时间为60秒,则我们最多有4个字典,并且每20秒添加一个新字典 - 新密钥被放置在其中,并删除第四个字典-其中我们将拥有在60秒前添加的密钥。这使得清理非常快,代价是检索时间会增加,您需要在4个字典中查找而不是一个(RAM使用量增加了33%)。
所以最终的问题是:是否有更好的解决方案?或者也许我错了,提到的某些解决方案(逐个删除密钥)会更好,更快?我不想重新发明轮子,但在网络上找不到任何好的解决方案。
3个回答

1

只有实验才能告诉你哪个更好。

这里是另一个简单的想法:按照到达顺序将所有键链接成链表。每次检索键时,从列表开头迭代并删除所有过期的项,从列表和字典中都删除。


你说得对,我应该尝试一下。已经检查过按顺序从4个字典中检索仍然适用于1微秒以下,所以这可能是正确的方法。但仍然想知道是否有人已经创建了类似的东西。 - kompas

0

哈希表的一种实现方式是为每个哈希值存储一个(key, value)列表。您可以将其扩展为为每个哈希值存储一个(key, 插入时间, value)列表。在获取和设置时,您可以在查找所需键时丢弃过期的项目。

是的,它可能会在哈希表中保留已过期的项目,但平均只有O(N)个项目,其中N是哈希表的大小。

这种方法的好处是没有并发清理,而且开销基本上是恒定的。

如果您关心速度,您将不得不使用C编写代码,而不是Python。


-1

正如我之前提到的 - 这是一个线程,添加另一个用于删除键将会带来很多同步问题 - 而且,这比仅仅按顺序处理并逐个删除要糟糕得多。 - kompas
通常情况下,轮询比通知效率低得多。在这种情况下,你不仅要轮询一个对象的过期时间,还要对整个集合进行轮询。祝好运! - necromancer
你可以在缓存本身上使用计时器通知而无需同步。只需将其排队通知,然后让您的单个线程偶尔清空队列并从队列中删除已通知的对象即可。我不明白定期检查100万个对象以找到1000个过期对象如何比从队列中处理1000个删除更有效率。唉... - necromancer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接