文章目录
前言
缓存带来的思考
一、缓存的引入
- 业务系统初期,数据库可以承担读写压力 应用直接和DB交互
- 业务量大规模增长,DB查询压力和耗时都在在增长,引入分布式缓存,减少DB压力的同时,提高QPS
- 分布式缓存 成为性能瓶颈,高频的QPS,缓存驱逐以及网络抖动,都会影响系统稳定性,引入本地缓存 减轻分布式换的压力 减少网络以及序列化开销
二、读写的性能提升
读性能优化:直接命中缓存 通过内存操作 避免磁盘IO 提高吞吐
写性能优化:写操作直接操作内存 让磁盘IO批量处理 顺序落盘
1. 读缓存Cache
- 本地缓存
Guava
:是Google Fuava中的一个内存缓存模块,用于将数据缓存到JVM内存中。Caffeine
:高性能的Java缓存库,使用Window TinyLfu清理策略,它提供了接近最佳的命中率。Ehcache
:纯Java的进程内缓存框架OHC
:全称为 off-heap-cache,即堆外缓存,是一款基于Java 的 key-value 堆外缓存框架。
- 分布式缓存
Memcached
:高性能的服务器内存缓存软件Redis
:完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库
- 应用
多级缓存
:CPU-> 堆 -> 内存
2. 写缓存Buffer
- 文件缓存
-java BufferedWriter
:Java语言中的缓冲流。
-Mysql InnoDB Buffer
: Mysql中InnoDB中的缓冲区。Hbase MemStore
:Hbase 中的操作缓存区。
- 网络缓存
SO_RCVBUF , SO_SNDBUF
- 应用
redis缓冲入账
三丶缓存Miss
缓存需要在有限的容量内 保持热点数据的常住 需要达到性能和成本平衡
1. 回收算法
-
LRU
- 如果严格执行LRU 每次遍历全部key 获取最近最少使用的key 去执行淘汰
- 耗时长 资源消耗大
-
近似LRU
- 通过活跃度 分离出活跃key和待回收key
- 回收时,关注待回收key既可
- 回收算法使用链表或者树的结构 使key按空闲时间有序
- 在缓存读写更新时 辅助回收的数据结构会同步更新 带来存储和计算成本较高
-
Redis 采用近似LRU实现
- 随机采样固定key
- 淘汰掉空闲时间最长的
- 有一定几率 会淘汰掉最近被访问的key
-
避免短期大量失效
- 避免某个时间节点 大量缓存同时失效 导致流量打到DB 降低系统性能和稳定性
- 利用随机数 打散缓存失效时间
四丶缓存一致性
1.尽量保证DB和缓存中数据一致性
2.常用 Cache aside 设计模式(更新数据库后,失效缓存)
3.避免使用非常规的缓存设计模式(先更新缓存、后更新DB | 先更新DB、后更新缓存(cache aside是直接失效缓存))
缓存设计模式
1. cache aside
业务系统常用设计模式,优先更新数据库,再失效缓存,缓存中的内容是不做更新操作的,只有写入和删除操作。
缓存污染
- 过期时间: 设置一个过期时间,短时间内数据不一致。
- 延迟双删 :主线程失效缓存后,将失效指令放入延时队列,另一个线程轮询队列获取指令并执行。
- CDC同步:通过canal订阅MySQL binlog的变更,上报给Kafka,系统监听Kafka消息触发缓存失效。
2. Read/Write through
核心策略:以缓存为操作为主,数据存先存在于缓存,缓存的数据是不会过期的。
Read Through
:先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库中同步加载数据。
-Write Through
: 先查询要写入的数据在缓存中是否已经存在,如果已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中。如果缓存中数据不存在,我们把这种情况叫做Write Miss(写失效)。Write Miss解决方式
- Write Allocate(按写分配):做法是写入缓存相应位置,再由缓存组件同步更新到数据库中
- No- write allocate(不按写分配):做法是不写入缓存中,而是直接更新到数据库中3
适用场景
用于读操作较多.相较于Cache aside而言更适合缓存一致的场景.
使用简单屏蔽了底层数据库的操作,只是操作缓存.
这种方式其实可以以Redis为存储,对数据的持久性要求较低的.
3. Write Back(Write behind)
Write back是相较于Write Through而言的一种异步回写策略,异步写可以减少与物理磁盘存储的交互,也可以进行合并写等优化。
适用场景
用于读少写多的场景
Linux系统的页缓存和MySQL InnoDB 引擎的Cache Pool其实就是使用的WriteBack策略.
相较于Write through 而言拥有更高的写入性能
总结
上述文章记录了一下常用的缓存和缓冲,作为个人见解,不做参考依据,详情请参考官方文档。