缓存(cache)机制

缓存数据分布模式 #

分片模式 (sharding) #

数据正交分散到大量机器, 可以做到线性的可伸缩性, 但是实现可用性比较困难。还有一个好处是可以通过集群做负载均衡来实现数据的管理。 根据CAP理论, 在高可用的场景下, 数据分区的容忍性需要牺牲一定的一致性。 相应各个副本的同步策略也有不同, 主要可分为同步和异步方式。由客户端做一致性hash把数据分片存放到服务端。

复制模式 #

数据在集群中存在多个副本。 在本地缓存的集群中,数据会复制到所有的节点中,没有网络延迟和等待时间的集群成员都是可用的。 多副本通过低延迟访问来提供高性能。 在修改数据时需要复制新的版本数据到所有的副本, 在高并发修改的场景下会限制系统的可伸缩性, 副本数不会调的太高。

本地缓存 #

在同一机房内的, 需要适量考虑本地cache, 数据压缩传输等以节省内网数据传输量 。 跨机房的缓存有地域区分,用户往往访问同一机房, 这样可以做本地的cache。 机房之间通过队列的方式进行异步和压缩传输,以提高用户请求的相应度。

缓存与场景 #

1. 非共性数据缓存 eg. 微博, 博客个人首页 #

问题:缓存所有的数据性价比不高, 命中率不高 解决方案:

I. 热点缓存。 #

只缓存那些热点的数据。可以缓存在线的用户, 缓存热销的商品, 缓存热点用户的数据。热点规则表示如何匹配到一个热点,即这个查询请求是否请求了热点数据。 根据2/8原则,小部分的数据占用了大部分的访问量。 这也就是twitter page cache 是40%,而不是90%的原因。  

II. 非热点数据, #

可以采用nosql技术(redies),可以把它看成可持久化的缓存。 原理类似虚拟内存,理论上不受内存大小的限制。使用NoSQL来做缓存,我们可以把一些不常访问、不怎么更新的数据也缓存起来。比如论坛、新闻的老数据、数据列表的靠后的页面,虽然用户访问不多,但是搜索引擎爬虫会访问,也可能导致系统负载上升。 从外存拿数据减少了计算的开销 ,由于其数据库结构的简单,从磁盘获取一次数 据也比从数据库一次耗时的查询划算很多。

III. read-only缓存 #

缓存是read-only的, 如果有cache数据的更新, 把cache置为失效的。 如果有多个副本,这样做能够减少replication更新数据的开销, 只需要发送置失效的消息即可。

2. 高并发更新场景 #

I. 悲观锁方案 #

高并发更新, 缓存会超时的场景可以使用mutex锁。如 首页top 10, 由数据库加载到memcache缓存n分钟 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库 在加载数据库之前先增加一个mutex key作为锁, 成功之后再去做加载数据库, 如果加锁失败则sleep,之后重试读取原cache数据。为了防止死锁,锁也需要设置过期时间。

II. 乐观锁方案 #

MVCC是后验性的,读不阻塞写,写也不阻塞读,等到提交的时候才检验是否有冲突,由于没有锁,所以读写不会相互阻塞,从而大大提升了并发性能。修改过的副本带着版本号元数据, 多个副本在合并时, 根据版本检测冲突, 并合并数据。

Memcache 通过客户端cas命令实现乐观锁。 Jboss在3.0实现了mvcc。 MVCC 提供了非阻塞 (non-blocking) 读操作 ( 它并不会去阻塞 wirter threads) ,在避免死锁的同时也提供了更高级的并发机制。它采用了 fail-fast 机制,如果写操作得到了一个 write lock ,那么它们也是依次进行,不允许重叠。

Redies作为缓存的最佳实践 #

  1. 对于全局公用的,构建成本比较低的数据, 可以采用一致性hash, 无复制, 无持久化的方案。 如果缓存crash了,可以快速重新构建。
  2. 对于与用户相关的, 一致性要求比较低的, 构建成本较低的, 可以采用多对一的复制方式,多个小容量的节点复制到同一个大容量的节点, 但不提供持久化, 提供较高的可用性。
  3. 对于与用户相关的,一致性要求比较高的, 构建成本比较高,但存储占用量不高的场景下, 需要持久化, 并且一对一的复制方式, 提供最高的可用性。

案例: Twitter缓存体系 Twitter: 逻辑缓存
- page cache api - fragment cache 1. 原始数据的冗余 2. 结构上的冗余 数据源cache - vector cache - Row cache

  • Page, fragment - 全局与局部的分离, api, 业务逻辑
  • Vector, row cache – 索引与内容的分离
  • Google gfs cache

缓存类型: Read-through 读贯穿 Write-trrough 写贯穿 Write-behind

参考 #

  1. NoSQL架构实践(三)——以NoSQL为缓存
  2. 大型网站架构系列之五,缓存策略设计概要 失效
  3. Memcache mutex设计模式
  4. 深入理解JBoss Cache3.0——Naga *
  5. 极端事务处理模式:Write-behind缓存
  6. 多版本并发控制(MVCC)在分布式系统中的应用