我在redis中存储了一堆实时数据。我在所有按键上设置了14400秒(4小时)的TTL。我已经将maxmemory设置为10G,目前没有足够的空间来容纳4小时的内存数据,而且我没有使用虚拟内存,所以redis在数据到期之前将其逐出。
我可以使用redis驱逐数据,但我希望它首先驱逐最旧的数据。因此,即使我没有完整的4小时数据,至少我可以获得一些数据范围(3小时,2小时等),并且没有任何空白。我试图通过设置maxmemory-policy=volatile-ttl
来实现这一目标,认为最旧的密钥将首先被驱逐,因为它们都具有相同的TTL,但它不是那样工作的。似乎redis有点随意地驱逐数据,所以最终我的数据存在差距。例如,今天2012-01-25T13:00的数据在2012-01-25T12:00之前的数据被驱逐。
是否可以将redis配置为始终首先逐出旧数据?
以下是我的redis.cnf文件中的相关行。如果您想要查看更多的配置,请告诉我们:
maxmemory 10gb
maxmemory-policy volatile-ttl
vm-enabled no
答案 0 :(得分:30)
AFAIK,无法将Redis配置为始终首先逐出旧数据。
当在maxmemory-policy中选择* -ttl或* -lru选项时,Redis不使用精确算法来选择要删除的键。精确算法在内存中需要额外的列表(用于* -lru)或额外的堆(用于* -ttl),并使用普通的Redis字典数据结构进行交叉引用。在内存消耗方面它会很昂贵。
利用当前机制,驱逐发生在主事件循环中(即,在执行每个命令之前在每次循环迭代时检查潜在的驱逐)。在内存回到maxmemory限制之前,Redis随机选择n个密钥的样本,并选择最多空闲的一个(对于* -lru)或最接近其到期限制的一个(对于* -ttl)。默认情况下,只考虑3个样本。结果是不确定的。
提高此算法准确性并缓解问题的一种方法是增加所考虑的样本数(配置文件中的maxmemory-samples参数)。 不要设置得太高,因为它会占用一些CPU。它是逐出精确度和CPU消耗之间的权衡。
现在,如果你真的需要一致的行为,一个解决方案就是在Redis之上实现你自己的驱逐机制。例如,您可以添加一个列表(对于不可更新的键)或一个有序集(对于可更新的键),以便跟踪应首先被驱逐的键。然后,添加一个守护程序,其目的是定期检查(使用INFO)内存消耗并查询列表/有序集的项目以删除相关的密钥。
请注意其他缓存系统有自己的方法来处理这个问题。例如,对于memcached,每个slab有一个LRU结构(取决于对象大小),因此驱逐顺序也不准确(尽管在实践中比Redis更具确定性)。