我正在尝试设计一个高速缓存服务器,该服务器将存储数据库查询的查询和结果键,从而减轻其负担。
可能是这样的:
if Cache.isSet(query):
return Cache.get(query)
else:
result = db.run(query)
Cache.set(query, result)
return result
我打算设计的缓存属性:
我正在尝试为URL缩短器创建此缓存,但希望将其扩展为完整的缓存服务器。 我面临的问题是:
我该如何解决?
答案 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,他们通过尝试读取密钥时的时间戳来解决这个问题。如果生存时间已过期,则删除密钥并返回缓存未命中。