最近在思考一个问题:缓存。
很可惜最后没有能实现自己的想法,就在这里做个记录好了。
出于限制条件,我没办法使用redis这类缓存数据库,所以在思考node轻量级缓存的操作,简单来说就是数据存储在一个变量,放在内存里。
情况
我有一个完整的网站,前后端和数据库都是完备的。
需求方提供了两个数据源,需要我们提供一个页面查询这两个数据源的数据显示,并提供添加数据到我们数据库的操作。查询是由多个key来筛选数据。
他们提供的数据相对稳定,为了提高查询效率,避免网络因素造成的延迟我打算做一个缓存,主要是这个以前没做过比较好玩。
基础了解
在深入理解缓存这篇文章里面我了解了缓存的基本知识,不过后面java部分的我就没有看了,写的挺不错的。
我主要了解了里面的基础概念:
缓存主要是利用空间换时间的算法,最关键的是内部的淘汰算法。
- 命中率
- 最大元素
- 淘汰算法
FIFO,LRU,LFU,随机清除 - 缓存穿透
- 缓存雪崩
- 脏数据
数据格式统一
我遇到的第一个问题就是数据结构不一致。这个当时我是有两种考虑,一种是不管他,直到你存储的时候再转换就可以了。另一种是从一开始就将数据结构统一。两种方式说不上来那种比较好,比较一下:
- 第一种
无效率问题,但是可能导致后续处理流程麻烦 - 第二种
有处理效率问题,但是后续不用再考虑数据结构的问题了
我为了避免麻烦,采用了第二种策略,用了async控制流程。
当然不管是第一种还是第二种,你都需要一个数据结构统一函数。
缓存淘汰算法
关于算法的选择,我看了传送门前两篇的文章,特别是看到node-cache 700多颗星和他的源码感慨,好眼红!!!
node-chche主要是采用了超时淘汰,就是给每个数据设置一个超时时间,超过时间自己杀死自己。:)每次put会刷新超时时间。基本的数据段为value+timeout。
在Node.js中搭建缓存管理模块主要介绍从数据结构设计到淘汰算法的这个那个过程。淘汰算法采用了LRU和LFO两种。时间或计数作为一个维度来决定数据的淘汰与否。同时设置了最大资源占用,还有最后的智能选择也是很有意思的。
当时我选择我的淘汰算法的时候完全不知道应该用哪种,我总想采用第二种里面的一种思路,不过我总想利用时间和计数形成一个二维选择数据,就是由时间和计数共同决定数据的淘汰。简单的想法就是时间作为第一维度,计数作为第二维度。每次命中单个数据刷新超时时间,如果计数达到一定的频率,就延长超时时间,利用计数形成二级缓存,以此来达到更高的命中率。或者是计数作为第一维度,时间作为第二维度。这是我的一点思考。
数据一致性
这里是我还没有思考的部分,如果我缓存了一个数据,数据源方面改了,怎么能保证他的数据一致性?这里我是利用crypto进行hash存储,比对来保证数据的一致,但是这种修改会导致的脏数据就没办法处理了。最后的杀手锏是提供给用户一个清空缓存的按钮。:)
总结
其实除了我提到的这些,还有很多其他的问题,两个数据源怎么统一,整个流程模块的拆分,缓存数据怎么存储,多个key怎么利用才能尽可能避免缓存穿透等等,虽然没做出来这个但是收获还是很多。
传送门
在Node.js中搭建缓存管理模块
node-cache 模块 node.js 轻量级缓存管理使用及源码分析
memory-cache
深入理解缓存