缓存整理
2020-12-01 11:11:38 20 举报
AI智能生成
缓存知识整理
作者其他创作
大纲/内容
存储
外存
持久化
硬盘,U盘,软盘等
获取数据慢,IO存取比较耗时
内存
机器重启,数据消失
数据读取速度快
定义
将外存的数据放到内存上的载体。通常使用map来进行缓存
是一种空间换时间的思想
示例
CPU的一级二级缓存
maven加载依赖的顺序,先本地仓库,然后本地服务器参考,最后去远程仓库查找
数据库的索引
京东仓储
指标
缓存命中率
从缓存读取数据的次数/总读取次数的比率,越高越好
总读取次数=从缓存读取次数+从慢速设备读取的次数
移除策略
在缓存满的时候,移除缓存的策略
策略
FIFO
先进先出,最先放入缓存的数据被移除
LRU
最久未使用,使用时间距离现在最久的数据被移除
LFU
最近最少使用,一定时间内使用次数最少的数据被移除
TTL
存活期,数据从缓存中创建的时间点到它到期的一个时间段
TTI
空闲期,一个数据多久没被访问则从缓存中删除的时间
Java中的实现
基于注解
Spring Cache 并非具体的缓存技术,而是基于各种缓存产品(如 Guava、EhCache、 Redis 等)共性进行的一层封装,让用户更加专注于应用层面。 具体的底层缓存技术究竟采用了 Guava、EhCache 还是 Redis,只需要简单的配置就 可以实现方便的切换。
主要接口
org.springframework.cache.Cache: 缓存本身
org.springframework.cache.CacheManager: 对缓存的处理和管理
使用
声明缓存
@Cacheable("books")
public Book findBook(ISBN isbn) {...}
public Book findBook(ISBN isbn) {...}
用法很简单,在方法上添加@cacheable 等注解,表示缓存该方法的结果。 当方法有被调用时,先检查 cache 中有没有针对该方法相同参数的调用发生过,如果有, 从 cache 中查询并返回结果。如果没有,则执行具体的方法逻辑,并把结果缓存到 cache 中。当然这一系列逻辑对于调用者来说都是透明的。
开启Spring的Cache功能
<cache:annotatiion-drivenn />
@EnableCaching
后端配置
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { return RedisCacheManager
.builder(connectionFactory) .cacheDefaults(
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(20))) //缓存时间绝对过期时间20s .transactionAware()
.build(); }
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { return RedisCacheManager
.builder(connectionFactory) .cacheDefaults(
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(20))) //缓存时间绝对过期时间20s .transactionAware()
.build(); }
缓存key的生成
其他操作
@CachePut(增加/修改)
应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存。
@CacheEvict(删除)
应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据
@Cacheable(查询)
应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有 再调用方法获取数据,然后把数据添加到缓存中
问题
缓存一致性问题
数据更新操作才会导致缓存一致性问题。
描述
数据库和缓存更新,容易出现数据库和缓存数据不一致的问题
问题:同时有一个请求 A 进行更新操作,一个请求 B 进行查询操作。可能出现:
(1)请求 A 进行写操作(key = 1 value = 2),先删除缓存 key = 1 value = 1 (2)请求 B 查询发现缓存不存在
(3)请求 B 去数据库查询得到旧值 key = 1 value = 1
(4)请求 B 将旧值写入缓存 key = 1 value = 1
(5)请求 A 将新值写入数据库 key = 1 value = 2
(1)请求 A 进行写操作(key = 1 value = 2),先删除缓存 key = 1 value = 1 (2)请求 B 查询发现缓存不存在
(3)请求 B 去数据库查询得到旧值 key = 1 value = 1
(4)请求 B 将旧值写入缓存 key = 1 value = 1
(5)请求 A 将新值写入数据库 key = 1 value = 2
注意⚠️
上面的情况,缓存中的数据永远都是脏数据
建议
缓存双删,进行两次删除操作。先删除缓存,在更新数据库,再此删除缓存(第二次删除可异步)
第二次删除后,数据要从数据库获取,保证缓存和数据库的一致性。保证数据的最终一致性
伪代码
缓存同步方案
实时同步更新
每次更新数据库之后,都对缓存进行更新,通过编码实现
优点
数据实时更新,保证强一致性
缺点
代码耦合,对业务代码有侵入性
准实时更新
更新数据库后,不立刻更新缓存,而是异步更新缓存。可通过发布订阅/MQ实现。
优点
与业务解耦
数据同步延迟较短
能保证最终一致性
缺点
实现复杂,架构较重
缓存失效机制
基于缓存本书的失效机制。跟缓存设置过期时间,过期后再去数据库获取数据存入缓存
优点
实现简单
不需要引入额外的逻辑
缺点
数据同步延迟不好控制。存在缓存击穿/雪崩的情况
定时任务更新
采用任务调度框架,或者定时任务,定期的从数据库获取数据更新到缓存
优点
与业务解耦
实现简单
缺点
不保证一致性
依赖定时任务
缓存雪崩
描述
缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压 力过大甚至 down 机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩 是不同数据都过期了,很多数据都查不到从而查数据库。
解决办法
key设置不同的过期时间
加锁,控制对数据库的访问
缓存预热
使用集群
缓存击穿
描述
缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于 并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力 瞬间增大,造成过大压力
解决办法
加锁,控制对数据库访问的数量
设置数据用不过期,物理不过期,逻辑上写代码更新
缓存穿透
描述
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为 id 为“-1”的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导 致数据库压力过大。
解决办法
布隆过滤器
redis中存储空结果,设置较短的过期时间
0 条评论
下一页