JavaJVM · Java虚拟机原理 · JVM上语言·框架· 生态系统Java入门基础

服务端的应用缓存设计

2018-12-15  本文已影响17人  liaowenhao

1. 类型

客户端缓存

缓存可以存储在客户端(操作系统或浏览器、服务端、或者是独立的缓存系统中。

CDN缓存

CDN也可以被认为是一种缓存。

Web服务器缓存

反向代理或者像Varnish这样的缓存服务可以直接保存静态的或动态的缓存内容。Web服务器也可以缓存请求直接响应客户端从而避免请求再次触达应用。

数据库缓存

我们的数据库服务在默认的配置或者稍微针对通用场景进行优化的情况下通常包含不同级别的缓存,针对特定的使用场景进行适当的调整可以进一步提高性能。

应用缓存

像Memcached和Redis这种内存key-value缓存服务,通常是置于应用和数据库服务之间,因为数据存储在内存中,因此这要比将数据存储在磁盘的数据库要快的多。但是内存与磁盘相比往往受限于空间,因此用类似LRU这种缓存淘汰算法将相对较少访问的”冷”数据从内存置换出来将访问频率较高的“热”数据放入内存。

2. 应用缓存

通过数据库服务前置缓存服务,可以有效吸收不均匀的负载和抵挡流量高峰

2.1 缓存级别

查询级别缓存

每当我们查询数据库的时候,将查询(比如SQL)进行hash并作为key和查询结果关联存储,这种方法会遇到缓存过期的问题:
对于复杂的查询很难删除缓存的结果;
缓存粒度较大,如果查询结果中只有丁点数据被更新,则整个查询都要过期;

对象级别缓存

对象级别缓存是将数据看做对象:
如果数据被修改则将数据从缓存中移除;
使用异步的任务来更新缓存;

2.2 数据读取

通用策略是Lazy load (Cache-Aside)


Lazy load策略 Lazy load实现

2.3 一致性 [难点]

现状

脏数据,简单通过设置过期时间(TTL)来缓解,当时间过期将发生强制更新缓存

问题

一致性问题,需要处理缓存中的数据与原数据不一致的问题
增加了软件架构的复杂性
缓存过期主要体现在何时更新缓存上

2.4 缓存更新策略

缓存更新策略

3. 数据库缓存

3.1 SQL查询流程
SQL查询流程
3.2 缓存类型

a. 执行计划
b. SELETE查询结果 (MySQL支持)

3.3 命中条件

匹配SQL/Version
无不确定数据

3.4 消耗

所有SQL强制查询
某些场景下的更新(碎片,内存,修改)会导致缓存失效
并发分配,失效的时候可能导致僵死

3.5 存储

缓存采用内存中的哈希引用表,SQL结果使用缓存数据块存储。


缓存数据块
3.6 数据库缓存策略调整
image.png

4. Redis接入

数据库/缓存/消息中间件

4.1 单线程

问题

采用基于内存的,单进程单线程模型, KV 数据库。
单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),其他模块仍用了多个线程。
事件驱动、所有命令处理在一个事件循环中。

应对
  1. 避免大key
    string value 小于限定值
    hash/set/zset 元素小于限定值
  2. 避免使用长时间阻塞的命令
    禁用 keys/flushall 等命令
    大key的平滑删除
  3. 避免过热的key
    最大支持的qps有上限, 热key分拆

4.1 内存

问题

所有数据都存放在内存中, 时延低

应对
  1. 避免单实例容量过大
    单实例:有目标上限
    存储集群: 有目标上限的内容和节点
    其他选择:考虑HBase/ABase
  2. 控制key的生命周期,redis不是垃圾桶
  3. 打散过期时间,防止集中过期
扩容
  1. 水平扩容 -通过增加分片实例完成扩容
    优点:可扩展
    缺点:扩容流程长,对业务有影响,避免高峰时期操作
  2. 垂直扩容 -直接修改配置内存值
    优点:对业务无损
    缺点:单实例内存上限

4.1 持久化

问题
  1. 磁盘的持久化:一般配置秒级 sync,最多丢失秒级的数据
    主从同步:异步方式,遇到主从切换后,同步中的数据丢失;
  2. 数据淘汰策略:
    noeviction:无逐出
    allkeys-lru:默认的逐出策略(近似的LRU)
应对
  1. 不要将 redis 当做高可靠的存储来使用

5 应用缓存的架构设计参考

CacheManager

模型管理对象,可以是多实例的,也可以是单实例的。

Cache

通过 CacheManager 创建出来的缓存容器,内部包含了真正的缓存承载体,至少开放 add/remove/flush 等接口。

CacheMap

真正的缓存承载体,大致上都是一个 Map,各种类型的 Map。

CacheEntity

缓存条目,相当于 CacheMap 里面的每一条 Entry。

CacheEvent

缓存事件,比如 CacheEntity 的创建、更新、删除等等。

CacheEventListener

缓存事件相应的监听器。

CacheEvictionAlgorithm

缓存淘汰算法,常见的有 LRU、LFU、FIFO 等等。

客户端缓存

形式

文件/内存/轻量级DB

场景

配置文件
变化少的数据,优化离线体验
最近缓存(Http& Feed &Image)

图片缓存-Fresco设计

图片缓存是客户端比较复杂的缓存和重要的一块,参考Fackbook开源的Fresco设计:


Fresco架构设计
上一篇下一篇

猜你喜欢

热点阅读