如何设计本地缓存、有哪些坑需要避免
背景
前一篇文章提到分布式缓存与本地缓存。 分布式缓存操作简单风险小, 能够服务共享缓存,提高系统整体的伸缩性和可用性。但能扛的量还是稍小一些, 本地缓存能扛极高的,特别是也有着非常优秀的程序 性能。 但同样本地缓存的风险也是最大的。 操作不慎,一致性,问题会非常大,而且会导服务的OOM。
设计本地缓存该注意 什么
本地缓存核心是K V形式的存储。在我的理解下核心有四个点:
第一个是你的数据结构K要保证唯一性, value尽量的精简。
第二个因为是本地的数据,要保证并发线程安全问题。
第三个是缓存数据的上限,不要太多, 而且必须要有淘汰策略,避免服务OOM。
第四个一定要有 过期时间, 避免数据一直被本地缓存,无法保证数据的最终一致。
常见的淘汰策略
最常见的FIFO、LRU、LFU这些。
都很好理解,第一个就是常见的队列,先进先出, 是复杂度最小的一个淘汰策略,虽然没有极端情况下是一个比较好的选择, 比如你缓存的数据,他就是跟着时间不断再更新。
LRU也比较常见,他的核心思想的是把最近的时间没有访问的数据淘汰掉, 实现也很简单,每次把新插入的缓存数据,或者说新访问缓存数据添加到列表的头部,当内存不够的时候把尾部的删除就好。
LFU是最小频次使用,每次会把使用次数最小的数据删掉。 相当于给每一个缓存的数据增加了一个计数功能,然后再按照计数进行排序。
如何避免本地缓存一致性问题
第一个就是,一定要给缓存的数据增加过期时间,避免长时间不过期。
第二个因为本地缓存,几乎每一台实例都会缓存一部分数据, 他不像分布式缓存一样可以共享缓存,所以如果要更新, 常见的有两种方案:
第一可以靠可以借助配置中心来实现, 可以异步监听配置中心的变化,每台实例更新自己的缓存数据。
第二是靠配置中心MQ的广播, key使用rocketMQ的消息分发, 将变化的配置实时的广播到每台实例。