在互联网产品中,缓存无处不在。当一个网站前期请求量少,服务响应很快,当随着请求增加响应越来越慢。这时需要对请求的入口合并、业务调整、底层代码重构、数据库SQL与表等等优化后提高响应最终提升整体的性能,也可以引入缓存以提高吞吐量。但是引入缓存也带了维护的问题,比如脏数据的问题、缓存数据更新的策越等等。
缓存的存在的场景
例如
- 浏览器缓存包括静态资源js、css、图片、video等数据
- 后端请求数据的缓存
- 对象缓存
- 网络数据的读取写入缓存
- APP内数据的缓存
- CPU一级、二级缓存
等等非常的多。
命中率
是衡量缓存的一个重要的指标
命中率 = 从缓存Get数据的次数 / 请求缓存总次数(包括load db、null等)
淘汰策略
- LRU:
LRU(least recently used)
最近最少使用策略,每次请求动态刷新数据最后一次的使用时间
,当触发淘汰时,清除最久使用的元素。
适合热点数据
不适合存储类似系统配置的数据,不是热点数据,但是却不能淘汰。
- FIFO:
FIFO(first in first out)
当达到触发清理时机时(空间不足或者达到元素上限)最先进入的元素会被优先处理掉,依赖元素的创建时间,
适合使用实效性
的场景,例如日志、指标采集等数据。 保护最新的数据
但是如果先进入的数据为热点数据或者系统常量配置。不适合
- LFU:
LFU(less frequently used)
最近很少使用策略,无论是否过期,根据元素的被使用次数
判断,清除使用次数较少的元素释放空间。
策略算法主要比较元素的hitCount(命中次数)。在保证高频数据有效性场景下,可选择这类策略。
- W-TinyLFU(Window Tiny Least Frequently Used)
算法:当一个数据进来的时候,会进行筛选比较,进入W-LRU窗口队列,以此应对流量突增,经过淘汰后进入过滤器,通过访问访问频率判决是否进入缓存。如果一个数据最近被访问的次数很低,那么被认为在未来被访问的概率也是最低的,当规定空间用尽的时候,会优先淘汰最近访问次数很低的数据;
优点:使用Count-Min Sketch算法存储访问频率,极大的节省空间;定期衰减操作,应对访问模式变化;并且使用window-lru机制能够尽可能避免缓存污染的发生,在过滤器内部会进行筛选处理,避免低频数据置换高频数据。
缓存的容量
每台机器物理上都是有上限的,所以缓存的容量不能无限的增加,当达到物理的上限后,会导致物理机运行缓慢。
存在哪里
- 内存: 直接开辟内存进行数据存储,速度开,IO延迟低,掉电数据丢失。适合数据允许丢失,并且有一定的回源策略
- 磁盘: 采用文件方式存储。例如redis中的save动作、MySQL数据库。数据都会保存到磁盘,并且选择性的加到到内存,IO延迟高。成本低。数据不易丢失(全备、增量、快照等备份),
现有的缓存都是2者结合,优先内存,定期保存到磁盘。出现故障时从磁盘中恢复, 有时恢复数据会慢, 可以摘掉一部分流量
本地与分布式
- Guava Caffeine
本地缓存代表的产品Guava、EhCache、Caffeine(Spring 5优先推荐使用)
- memcahce redis
分布式缓存代表的产品memcache、redis其他NoSQL内存类产品
- 一致性算法
主要解约部分增加节点,不会对全部数据进行hash取模计算。
一致性Hash算法原理与实现
缓存击穿、穿透、雪崩
- 穿透: 缓存+DB都不存在,并且请求特点是,短时间、高密度的。
- 击穿: 大量请求并发查询同一条数据(同一个key)
- 雪崩: 在一个时刻,大量的缓存(不同的key)到期,将请求全部请求到DB
评论