转载请注明出处:http://carlosfu.iteye.com/blog/2269678
一、缓存的几种更新策略
从下面的表格看,缓存的更新策略大概氛围三种、本文将从一致性和维护成本两个方面对于三种缓存更新策略进行简要说明,因为这些东西比较理论和抽象、入哪里说得不对,欢迎拍砖
注:
1):一致性:缓存和真实数据源(例如mysql, hbase, elasticsearch等等)是否存在一段时间数据的不一致。
2):维护成本: 开发人员的开发和维护成本。
策略 | 一致性 | 维护成本 |
---|---|---|
LRU/LIRS/FIFO算法剔除 | 最差 | 低 |
超时剔除 | 较差 | 较低 |
主动更新 | 强 | 高 |
二、LRU/LFU/FIFO算法剔除
1、使用场景
通常用于缓存使用量超出了预设的最大值的时候(缓存空间不够),如何对现有的数据进行清理。例如FIFO吧最新进入的缓存的数据清理出去,LRU会把最近最少使用的清理掉
例如:Memcache使用的事LRU,具体Memcache是如何实现的这里就不在做赘述了,网上资料多得是。
例如:Redis使用的是maxmemory-policy这个配置作为内存最大值后对于数据的更新策略
配置名 | 含义 | 默认值 |
---|---|---|
maxmemory | 最大可用内存 | 不使用该配置,也就对内存使用无限制 |
maxmemory-policy | 内存不够时,淘汰策略 | volatile-lru |
- volatile-lru -> 用lru算法删除过期的键值
- allkeys-lru -> 用lru算法删除所有键值
- volatile-random -> 随机删除过期的键值
- allkeys-random -> 随机删除任何键值
- volatile-ttl -> 删除最近要到期的键值
- noeviction -> 不删除键,只返回一个错误
2、常用算法:
这里不再赘述,常用的算法有如下几种:
- FIFO[first in first out]
- LFU[Less Frequently Used]
- LRU[Least Recently used]
3、 一致性
可以想象,要清理的那些数据,不是有开发者决定的(只能决定大致方向,策略算法),数据一致性是最差的
4、维护成本
这些算法不需要开发者自己去实现,通常只需要配置最大maxmemory和对应的策略即可
开发者只需要有这个东西,知道是什么意思,选择自己需求的算法,算法的实现由缓存服务器实现
三、超时剔除
1、使用场景
就是通常我们所说的缓存过期时间设置,列入redis和memcache都提供了expire这样的API,来设置K-V的过期时间。一般来说业务可以容忍一段时间内(例如一个小时),缓存数据和真实数据(例如:mysql,hbase等等)数据不一致(一般来说,缓存可以提高访问速度,降低后端负载),那么我们可以对一个数据设置一定时间的过期时间,在数据过期后,再从真实数据源获取数据,我们可以容忍一个小时内数据不一致,但是涉及一些钱的方面,如果不一致可想而知
2、一致性
一段时间内(取决于过期时间)存在数据一致性问题,即缓存数据与真实数据源数据不一致
3、维护成本
用户的维护成本不是很高,只需要设置expire过期时间(前提是你的业务允许这段时间可能发生的数据不一致)
四、四、主动更新
1、使用场景
业务对于一致性要求很高,需要在真实数据更新后,要立即更新缓存里数据。
具体做法:例如可以利用消息系统或者其他方式(比如数据库触发器,获取其他数据源的listener机制来完成),通知缓存更新
2、 一致性
可以想象一致性是最高(几乎接近强一致),但是有一个问题:如果主动更新发生了问题,那这条数据很可能长时间不会再更新了(所以可以结合超时剔除一起使用,下面最佳实践会说到)
3、维护成本
相当高,用户需要自己来完成更新(需要一定量的代码,从某种程度上加大了系统的复杂性),需要自己检查数据是否真的更新了之类的工作。
五:最佳实践
其实最佳的实践就是组合使用
一般来说我们都需要配置超过最大缓存后的更新策略(例如:LRU)以及最大内存,这样可以保证系统可以继续运行(例如redis可能存在OOM问题)(极端情况下除外,数据一致性要求极高)。
一般来说我们需要把超时剔除和主动更新组合使用,那样即使主动更新出了问题,也能保证过期时间后,缓存就被清除了(不至于永远 都是脏数据)。