[转载]缓存系列文章(三)缓存常用更新策略对比(一致性)。

转载出处: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. 维护成本:

相当高,用户需要自己来完成更新(需要一定量的代码,从某种程度上加大了系统的复杂性),需要自己检查数据是否真的更新了之类的工作。

 

五、最佳实践

    其实最佳实践就是组合使用:

1. 一般来说我们都需要配置超过最大缓存后的更新策略(例如:LRU)以及最大内存,这样可以保证系统可以继续运行(例如redis可能存在OOM问题)(极端情况下除外,数据一致性要求极高)。

2. 一般来说我们需要把超时剔除和主动更新组合使用,那样即使主动更新出了问题,也能保证过期时间后,缓存就被清除了(不至于永远都是脏数据)。

[转载]缓存使用与设计系列文章(二)是否真的需要缓存?

转载出处:http://carlosfu.iteye.com/blog/2269678

一、缓存的成本和收益是什么:

 

既然要讨论是否真的需要缓存这个问题,就要知道缓存带来的成本与收益(好处、坏处)是什么?

收益 成本
缓存 + 后端存储(资源) 1. 加速读写

2. 降低后端负载

1. 数据不一致性

2. 代码维护成本

3. 架构复杂度

 

上面的表格应该清楚的表达了使用缓存后的收益和成本分别是什么。下面将进行详细的解析

 

二、缓存成本与收益详解:

 

1. 收益是很明显的,通常来说一个设计还不错的缓存系统,能够帮助你的业务实现加速读写,同时帮助降低了后端负载。

(1) 加速读写:通常来说加速是明显的,因为缓存通常都是全内存的系统,而后端(可能是mysql、甚至是别人的HTTP, RPC接口)都有速度慢和抗压能力差的特性,通过缓存的使用可以有效的提高用户的访问速度同时优化了用户的体验。

(2) 降低后端负载:通过缓存的添加,如果程序没有什么问题,在命中率还可以的情况下,可以帮助后端减少访问量和复杂计算(join、或者无法在优化的sql等),在很大程度降低了后端的负载。

2. 成本:

(1) 数据不一致性:无论你的设计做的多么好,缓存数据与权威数据源(可以理解成真实或者后端数据源)一定存在着一定时间窗口的数据不一致性,这个时间窗口的大小可大可小,具体多大还要看一下你的业务允许多大时间窗口的不一致性。

(2) 代码维护成本:加入缓存后,代码就会在原数据源基础上加入缓存的相关代码,例如原来只是一些sql, 现在要加入k-v缓存,必然增加了代码的维护成本。

(3) 架构复杂度:加入缓存后,例如加入了redis-cluster,一般来说缓存不会像Mysql有专门的DBA,很有可能没有专职的管理人员,所以也增加了架构的复杂度和维护成本。

 

三、如何选择?

 

如果当前系统的访问速度和访问量能够满足现有的要求,就不必增加缓存,其实像mysql并没有那么差,一台运行良好的Mysql,扛个QPS=1000没什么问题。

如果要加入选择了缓存,一定要能给出足够的理由,不是为了简单的show技术和想当然,最好的方法就是用数据说话:加速比有多少、后端负载降低了多少。

 

四、什么样的场景需要缓存?

 

在公司里,据我观察,无论怎么更新架构,使用各种新技术,但是80%的项目还是离不开SQL的,下面我们以SQL作为后端数据源、以Redis作为缓存层,说一下哪些场景是需要缓存的。

1、复杂开销大的计算、降低后端负载

以Mysql为例子,一些复杂的操作或者计算(例如大量联表操作、一些分组计算),如果不加

缓存,大量流量将在这些复杂计算的执行。

 

2. 加速请求响应

即使单条后端数据足够快(例如select * from table where id=?),那么依然可以利用redis/memcache将这些操作进行merge做优化(例如:cache(select * from table where id in(id1,id10….idK))),从而优化整个IO链的相应时间。

 

 

 

附图一张:

[转载]缓存使用与设计系列文章(一)缓存的一些基本常识。

 一、基本概念

 

1. Cache(缓存): 从cpu的一级和二级缓存、Internet的DNS、到浏览器缓存都可以看做是一种缓存。

维基百科: 写道
a store of things that will be required in the future, and can be retrieved rapidly.
(存贮数据(使用频繁的数据)的临时地方,因为取原始数据的代价太大了,所以我可以取得快一些)


 

2. Cache hit(缓存命中)(下图左)

When a data element is requested from cache and the elements exists for the given key.

3. Cahe miss(缓存未命中): 与Cache hit相反(下图右)

4. 缓存算法:缓存容量超过预设,如何踢掉“无用”的数据。

例如:LRU(Least Recently Used) FIFO(First Input First Output)Least Frequently Used(LFU) 等等

5. System-of-Record(真实数据源): 例如关系型数据库、其他持久性系统等等。

也有英文书叫做authority data(权威数据)

 

6. serialization-and-deserialization(序列化与反序列化):可以参考:序列化与反序列化(美团工程师写的,非常棒的文章)

后面也有单独文章去分析。


 

6. Scale Up (垂直扩容) 和 Scale out (水平扩容)

 

驴拉车,通常不是把一头驴养壮(有极限),而通常是一群驴去拉(当然每个个体也不能太差)。

 

 

服务器也是一样的道理,至少互联网是这样:

7. Write-through 和 write-behind

 

8.阿姆而达定律:用于计算缓存加速比

 

 

二、缓存的种类或者类型

 

1. LocalCache(独立式): 例如Ehcache、BigMemory Go

(1) 缓存和应用在一个JVM中。

(2) 缓存间是不通信的,独立的。

(3) 弱一致性。

 

2. Standalone(单机):

(1) 缓存和应用是独立部署的。

(2) 缓存可以是单台。(例如memcache/redis单机等等)

(3) 强一致性

(4) 无高可用、无分布式。

(5) 跨进程、跨网络

 

3. Distributed(分布式):例如Redis-Cluster, memcache集群等等

(1) 缓存和应用是独立部署的。

(2) 多个实例。(例如memcache/redis等等)

(3) 强一致性或者最终一致性

(4) 支持Scale Out、高可用。

(5) 跨进程、跨网络

 

4. Replicated(复制式): 缓存数据时同时存放在多个应用节点的,数据复制和失效的事件以同步或者异步的形式在各个集群节点间传播。(也是弱一致性)

这种用的不太多。

 

 

三、数据层访问速度:(作为开发人员要记住这些量级)