键值存储中的项目过期算法是什么?


10

我在考虑当前的键值存储如何实现项目的“到期日期”。目前,我有2种变体供您选择:

  1. 他们什么也不做(保留过期的数据),并且只在您执行操作时检查,例如,通过某些键进行GET。这里的问题是,如果您的内存有限,则过期的项目将不会被删除。
  2. 它们保留了其他数据结构,以便能够“最早过期”。我看到可以通过以下方式完成:

    storage_data = dict(key -> [value, expire_timestamp])
    expire_tree = SomeBinaryLikeTree(expire_timestamp -> [keys])
    

Answers:


6

删除缓存中过期条目的问题非常类似于垃圾回收,减去了引用计数的整个复杂性。

Nasza-Klasa的人们为Memcache提出了O(1)算法,如下所示:

似乎许多人出于某种原因认为释放过期的条目无法在O(1)中执行,甚至认为它需要Omega(N)操作。使用堆或其他优先级队列数据结构显然可以使您获得O(log N),但以下修补程序针对的是O(1)。这是通过每秒拥有一个存储桶,并通过查看到期时间将每个条目放入适当的存储桶中来实现的。然后在每一秒钟,我们仅从下一个存储桶中释放元素。显然,这是O(1)的摊销时间,但是可能会发生很多元素同时到期的情况,因此该修补程序对您愿意为每个请求执行的操作数量提供了固定的限制,使垃圾收集运行更顺畅。

参见附有代码的整个提案


谢谢。我也认为“存储桶”解决方案是一种方法。同样,“存储桶中的项目过多”也没有问题,因为您可以使用算法“取上次没有使用的存储桶,并在完成后取回”。
Kostiantyn Rybnikov 2012年

@k_bx:这就是他们提出双链表的原因,因此您可以返回到先前的存储桶。
vartec

如果存储桶大约是几秒钟,那么您根本不需要链表。要往前走,您只需减小键:)
Kostiantyn Rybnikov 2012年

@k_bx:将密钥减少多少?一秒?如果以前未完全清空的存储区是5分钟前该怎么办?减少1s 300次?
vartec

在第一次启动服务器时,将名为current_expire_bucket的变量初始化为某个值。然后,从current_expire_bucket开始运行清理,直到当前秒为止。清理结束后,您会睡一小段时间。如果服务器停止,那么您将再次经历相同的“过期存储区”,是的,但是它仅应在服务器停止时发生。
Kostiantyn Rybnikov 2012年

7

我认为键值存储太大,无法遍历所有kv对以找出哪些可以过期。我还假设每次读取访问都会刷新到期时间戳,因此只有一段时间未访问的项目才会过期。

面临的挑战是如何有效地找到所有可以到期的记录(每当需要进行清理时),还要有效地刷新每个读取访问的到期时间戳(因此我们必须在用于到期的结构中找到键)。

我的建议:将expiry_timestamps分组到存储桶中;例如,如果物品使用寿命8小时,则每小时要制造一个水桶。这些存储桶保存在链接列表中;到期时,将清空第一个存储桶,并减少列表。桶数是寿命/清理间隔。每个存储桶均包含应过期的所有键的hashSet。对哈希集中的所有键进行迭代足够有效。

在读取访问期间,程序将检查密钥当前位于哪个存储桶以及它现在属于哪个存储桶。在大多数情况下,它是同一个存储桶,因此无需采取进一步措施。否则,请从旧存储桶中删除密钥(从散列集中删除是有效的),然后将其插入新存储桶中。

   +--------------+   +--------------+   +--------------+
-->+ Expiry 08:00 +-->+ Expiry 09:00 +-->+ Expiry 10:00 +
   | KeySet       |   | KeySet       |   | KeySet       |
   +--------------+   +--------------+   +--------------+
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.