使用LFU设计缓存服务器以减少数据库负载

时间:2018-08-22 12:05:00

标签: python algorithm caching hashmap

我正在尝试设计一个高速缓存服务器,该服务器将存储数据库查询的查询和结果键,从而减轻其负担。
可能是这样的:

if Cache.isSet(query):
       return Cache.get(query)
else:
       result = db.run(query)
       Cache.set(query, result)
       return result

我打算设计的缓存属性:

  • 使用REST API将成为缓存服务器
  • 将使用哈希映射以键值形式存储在RAM中
  • Hashmap将被备份(间隔时间序列化到文件中)

我正在尝试为URL缩短器创建此缓存,但希望将其扩展为完整的缓存服务器。 我面临的问题是:

  • 如何确定要存储的键值对的数量?
  • 如果更改了数据库中的值,是否需要删除处理它的Query(Key)?

我该如何解决?

1 个答案:

答案 0 :(得分:0)

Redis的开发人员在Random notes on improving the Redis LRU algorithm上有一篇很好的文章,其中还介绍了LFU实现。 LRU算法的主要思想是在访问对象时使用时间戳标记对象。如果内存不足,请选择五个随机密钥并逐出最旧的时间戳。这是一种eventual concistency方法,您将无法找到逐出的确切最佳键,但是可以在宏级别上使数据集越来越好。主要好处是每个对象都有其自己的状态,您无需维护复杂的优先级列表即可跟踪驱逐的对象。该文档后来以LRU的想法为基础,但也展示了如何在无需太多工作的情况下将其转换为LFU算法。

  

如何确定要存储的键值对的数量?

使用尽可能多的内存。无限RAM的最佳情况是缓存整个数据集。使用受限的RAM,您将不得不查看您的访问模式。大多数情况下,是否存在一小部分“热”对象?然后确保尽可能多地将其缓存。

我怀疑您可能会遇到URL缩短器的一个问题是您的URL尾部会很长。也就是说,旧的URL很少访问每个URL,但是这些URL的数量如此之大,以致它们一起构成了数据库负载的很大一部分。在这种情况下,您可能需要考虑一个可以容纳整个数据集的高速缓存,或者以某种方式加快数据库查询的速度。长尾与热对象的不同之处在于,长尾对象很少被访问,以至于每次访问之间它们都会从高速缓存中逐出。没有适合长尾的缓存驱逐算法;您要么缓存整个长尾巴,要么专注于加快原始的未缓存访问。

  

如果DB中的值更改了,我是否必须删除处理它的Query(Key)?

是,或更新缓存。如果您的系统逻辑可以接受某些延迟,则可以在按键上使用生存时间。然后您逐出早于x秒的键。回顾一下Redis,他们通过尝试读取密钥时的时间戳来解决这个问题。如果生存时间已过期,则删除密钥并返回缓存未命中。