冷热分离一直是数据库和存储领域离不开的话题,特别是大数据的年代,数量和存储成本的矛盾需要冷热分离来解决。对于生产系统,不同数据库的特点不同,冷热分离机制和算法也不同。本篇文章讲一下内存数据库的冷热分离。

内存数据库最显著的特点是吞吐高、延迟低,但是内存数据库往往会对接一个外部存储,比如Redis的外存版本。这样就要求冷热分离算法的cost必须很低,才不会影响内存数据库的性能,或者说把影响降到最低。传统的内存cache替换策略是基于LRU或者LFU实现的。比如LRU的实现方式是一个链表,加一个hash表,链表相当于key value有序(根据最近访问规则的排序)队列,hash表帮助快速定位一个key在链表中的位置,免去遍历链表的开销。访问一个key后,需要定位这个key在链表中的位置,然后断开,再移到链表的头部。如果是LFU,那么更复杂一些,但是总体思想差不多,代码可以参考我的另一篇文章:Tieying Zhang:LFU代码实现zhuanlan.zhihu.com

在实际的内存数据库系统中(比如Redis外存版),我们不会把全部data都存在LFU中(那样维护开销以及存储开销都很大),而是会拿出一小部分data,比如redis就是拿出16个对象作为LFU的近似替代,保证这16个对象是比较冷的,即访问频次比较少的。那么如何选取这16个对象呢?最简单的方法:sampling,并且是随机sample,并且有人证明,随机sample就可以近似代表了全局data,最终的miss ratio不会差太多,具体怎么做呢?

每次有数据从外存换入的时候,要决定哪些对象被evict,这时我们从全表中sample出来k个对象和16个对象的频次相比。因为只有16个对象,所以就算是遍历也很快,最后换出k个最冷的。这里访问的频次被记录在每个kv的key里,这样新来的对象就可以插入了。

另外,上面提到内存数据库的特性是高吞吐和低延迟,冷热分离不适合使用机器学习的方式处理。对于非内存数据库,冷热分离实际上是个通用需求,涉及的技术主要包括survival analysis,实际上已经研究了很多年,常常用于医疗领域,比如生病的时间等。对应的模型有cox(survival regression的一种)等。另外,由于输入是访问的时间序列,需要考虑预测形式是下次访问的时间点,还是时间间隔,或者是访问次数,当然可以试试看哪个效果好。