解决缓存问题
1.解决Redis把内存爆满的三种方法1.1 定期删除1.2 惰性删除1.3 内存淘汰策略2. 缓存穿透——缓存击穿——缓存雪崩3. 如何解决线上缓存穿透问题3.1 缓存击穿(缓存失效)3.2 缓存穿透(数据删除)4. 基于DCL机制解决热点缓存并发重建问题实战5. Redis分布式锁解决缓存与数据库双写不一致问题实战6. 利用多级缓存架构解决Redis线上集群缓存雪崩问题1.解决Redis把内存爆满的三种方法
1.1 定期删除
让程序员均匀设置过期时间,Redis定时去扫描数据是否有过期的过期的删除掉,全盘扫描太浪费资源了采用的是随机选取一部分缓解内存压力,但是有一部分键值对每次都没有被随机选择算法选中。在定期删除的基础上添加了惰性删除
1.2 惰性删除
那些逃过随机选择算法的,一但被查询的时候先查看是否过期,过期就直接删除,,存在问题,还是有很多数据到了过期时间但是没有去查询删除而存在内存中,造成内存爆满。为解决内存不足时该如何解决最后出现了内存淘汰策略
1.3 内存淘汰策略
以下8种策略,给出了在内存不足时,该如果决策
2. 缓存穿透——缓存击穿——缓存雪崩
缓存穿透是某个热点数据访问缓存和数据库中都不存在(访问数据库中不存在的数据)
缓存击穿是某个热点数据访问缓存中不存在 数据库中存在(访问缓存中不存在的数据)
缓存雪崩是大量数据访问缓存都失效,大量请求去访问数据库把数据库给怼宕机了
3. 如何解决线上缓存穿透问题
过期时间均匀分布+热点数据永不过期
3.1 缓存击穿(缓存失效)
解决思路:
只需要加上过期时间随机值,能够保证上万条数据不同时过期,减少对数据库的压力,同一时刻缓存中还是有数据的
redisUtil.set(key, JSON.toJSONString(cookies), 24 * 60 * 60 , TimeUnit.SECONDS);
new Random().nextInt(30)60; 随机产生一个[0~3060)int类型的数值
redisUtil.set(key, JSON.toJSONString(cookies), 24 * 60 * 60 + new Random().nextInt(30)*60, TimeUnit.SECONDS);
3.2 缓存穿透(数据删除)
上万条数据同时请求数据,缓存中没有数据,去数据库中数据库中也没有数据,穿透所有的持久层
解决思路:
为了防止缓存穿透,在第一条数据进行请求的时候发现缓存和数据库中都没有要求请的数据,就在缓存中放一个空串{},下次再次请求的时,读取到缓存中的值,判断值如果是空串则返回null ,否则返回对应的值。
4. 基于DCL机制解决热点缓存并发重建问题实战
上万条请求同时请求某一条数据
方法一:
添加同步锁机制synchronized,,,,
(双重检测锁)解决突发热点并发重建导致DB压力暴增
让第一个请求先查Redis缓存,若不存在查DB,查到写入Redis缓存
后续的请求再访问Redis时,直接取值
synchronized(this){//Redis缓存中取数据,//缓存中不存在该条数据,请求DB,存到Redis中}
方法二:
使用Redis分布式锁
引入依赖
<dependency><groupId>org.redisson</groupId><artifactId>redissson</artifactId><version>3.6.5</version></dependency>
@Autowiredprivate Redisson redisson;RLock hotCacheCreateLock = redisson.getLock(key);hotCacheCreateLock.locak(); //相当于执行了setnx(k,v)// 加锁try{//Redis缓存中取数据,//缓存中不存在该条数据,请求DB,存到Redis中} finally {hotCacheCreateLock.unlock(); //删除锁 del k 删除key}
5. Redis分布式锁解决缓存与数据库双写不一致问题实战
解决办法:Redis 分布式锁
@Autowiredprivate Redisson redisson;RLock hotCacheCreateLock = redisson.getLock(key);hotCacheCreateLock.locak(); //相当于执行了setnx(k,v)// 加锁try{//Redis缓存中取数据,RLock updateCreateLock = redisson.getLock(key2);updateCreateLock.locak(); //相当于执行了setnx(k,v)// 加锁try{//缓存中不存在该条数据,读取DB中数据,并存到Redis中} finally {updateCreateLock.unlock(); //删除锁 del k 删除key2}} finally {hotCacheCreateLock.unlock(); //删除锁 del k 删除key}
优化:可以用读写锁
对读多写少进行优化——所有的读操作并行执行,读和写互斥串行执行
读数据库中的数据
@Autowiredprivate Redisson redisson;RLock hotCacheCreateLock = redisson.getLock(key);hotCacheCreateLock.locak(); //相当于执行了setnx(k,v)// 加锁try{//Redis缓存中取数据,//RLock updateCreateLock = redisson.getLock(key2);RReadWriteLock readWriteLock = redisson.getReadWriteLock(ke2)RLock rLock = readWriteLock.readLock();rLock.locak(); // 加读锁 setnx(k,v) try{//缓存中不存在该条数据,读取DB中数据,并存到Redis中} finally {rLock.unlock(); //删除锁}} finally {hotCacheCreateLock.unlock(); //删除锁 del k 删除key}
更新数据库中数据
RReadWriteLock readWriteLock = redisson.getReadWriteLock(ke2)RLock wLock = readWriteLock.writeLock();wLock.locak(); // 加写锁 setnx(k,v) try{//修改数据库中的数据操作} finally {wLock.unlock();}
读数据缓存锁优化
@Autowiredprivate Redisson redisson;RLock hotCacheCreateLock = redisson.getLock(key);//hotCacheCreateLock.locak(); //相当于执行了setnx(k,v)// 加锁hotCacheCreateLock.tryLock(2,TimeUnit.SECONDS); //等待2秒后锁失效(设置合适的时间)try{//Redis缓存中取数据,//RLock updateCreateLock = redisson.getLock(key2);RReadWriteLock readWriteLock = redisson.getReadWriteLock(ke2)RLock rLock = readWriteLock.readLock();rLock.locak(); // 加读锁 setnx(k,v) try{//缓存中不存在该条数据,读取DB中数据,并存到Redis中} finally {rLock.unlock(); //删除锁}} finally {hotCacheCreateLock.unlock(); //删除锁 del k 删除key}
6. 利用多级缓存架构解决Redis线上集群缓存雪崩问题
Redis单节点高并发最高10W+,,,瞬间来了几十W上百W的请求来查Redis中数据,Redis直接宕机了,,,缓存雪崩问题
web应用分流,,,
多级缓存——JVM进程级别缓存
JVM进程级别的缓存一般来说都是有容量上的限制
如果觉得《Redis缓存穿透-热点缓存并发重建-缓存与数据库双写不一致-缓存雪崩》对你有帮助,请点赞、收藏,并留下你的观点哦!