织梦可以做婚纱影楼网站吗,私人可以做org后缀网站吗,wordpress链接尾缀,携程旅行的网站建设缓存穿透 定义
缓存穿透 #xff1a;缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在#xff0c;这样缓存永远不会生效#xff0c;这些请求都会打到数据库#xff0c;造成数据库压力#xff0c;也让缓存没有发挥出应有的作用
解决方案
缓存空对象 当我们客户端…缓存穿透 定义
缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在这样缓存永远不会生效这些请求都会打到数据库造成数据库压力也让缓存没有发挥出应有的作用
解决方案
缓存空对象 当我们客户端访问不存在的数据时先请求redis但是此时redis中没有数据此时会访问到数据库但是数据库中也没有数据这个数据穿透了缓存直击数据库我们都知道数据库能够承载的并发不如redis这么高如果大量的请求同时过来访问这种不存在的数据这些请求就都会访问到数据库这个数据即使数据库不存在我们也把这个数据存入到redis中去这样下次用户过来访问这个不存在的数据那么在redis中也能找到这个数据就不会进入到缓存了但这样缓存大量空对象也会消耗内存 布隆过滤器 布隆过滤器其实采用的是哈希思想来解决这个问题通过一个庞大的二进制数组走哈希思想去判断当前这个要查询的这个数据是否存在如果布隆过滤器判断存在则放行这个请求会去访问redis哪怕此时redis中的数据过期了但是数据库中一定存在这个数据在数据库中查询出来这个数据后再将其放入到redis中假设布隆过滤器判断这个数据不存在则直接返回优点在于节约内存空间但会存在误判即过滤器判断该数据不存在是准确的但判断存在时就不一定准确误判原因在于布隆过滤器走的是哈希思想只要哈希思想就可能存在哈希冲突 解决思路
在原来的逻辑中我们如果发现这个数据在mysql中不存在直接就返回404了这样是会存在缓存穿透问题的
现在的逻辑中如果这个数据不存在我们不会返回404 还是会把这个数据写入到Redis中并且将value设置为空欧当再次发起查询时我们如果发现命中之后判断这个value是否是null如果是null则是之前写入的数据证明是缓存穿透数据如果不是则直接返回数据。 编码解决
由于布隆过滤器实现得较为复杂本项目采用方案一即数据库不存在数据时直接缓存空对象对查询商铺信息方法进行改造 Overridepublic Result queryById(Long id) {//根据业务代码组装keyString key CACHE_SHOP_KEY id;//从redis中获取商铺信息String shopJson stringRedisTemplate.opsForValue().get(key);//判断有值的情况if (StrUtil.isNotBlank(shopJson)) {//将json转化为shop对象直接返回Shop shop JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//对无值情况进行校验if(shopJson!null){return Result.fail(店铺不存在);}Shop shop getById(id);if (shop null) {//将当前的key的空对象缓存到redis中过期时间设置稍微短一点stringRedisTemplate.opsForValue().set(key, , CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail(店铺不存在);}//将数据库查询的数据写入缓存,并设置过期时间stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);//返回return Result.ok(shop);}
缓存雪崩
定义
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机导致大量请求到达数据库带来巨大压力。
解决方案 给不同的Key的TTL添加随机值使得key不会同时失效 利用Redis集群提高服务的可用性 给缓存业务添加降级限流策略 给业务添加多级缓存
缓存击穿
定义
缓存击穿问题也叫热点Key问题就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了无数的请求访问会在瞬间给数据库带来巨大的冲击。比如双十一做活动的热门商品数据
情景分析假设线程1在查询缓存之后本来应该去查询数据库然后把这个数据重新加载到缓存的此时只要线程1走完这个逻辑其他线程就都能从缓存中加载这些数据了但是假设在线程1没有走完的时候后续的线程2线程3线程4同时过来访问当前这个方法 那么这些线程都不能从缓存中查询到数据那么他们就会同一时刻来访问查询缓存都没查到接着同一时间去访问数据库同时的去执行数据库代码对数据库访问压力过大 解决方案 互斥锁 因为锁能实现互斥性。假设线程过来只能一个人一个人的来访问数据库从而避免对于数据库访问压力过大但这也会影响查询的性能因为此时会让查询的性能从并行变成了串行我们可以采用tryLock方法 double check来解决这样的问题。这一方案的好处是保证了数据的强一致性也就是每个线程查询的数据都是最新的数据 情景分析
假设现在线程1过来访问他查询缓存没有命中但是此时他获得到了锁的资源那么线程1就会一个人去执行逻辑假设现在线程2过来线程2在执行过程中并没有获得到锁那么线程2就可以进行到休眠直到线程1把锁释放后线程2获得到锁然后再来执行逻辑此时就能够从缓存中拿到数据了。 编码实现
核心思路相较于原来从缓存中查询不到数据后直接查询数据库而言现在的方案是进行查询之后如果从缓存没有查询到数据则进行互斥锁的获取获取互斥锁后判断是否获得到了锁如果没有获得到则休眠过一会再进行尝试直到获取到锁为止才能进行查询。如果获取到了锁的线程再去进行查询查询后将数据写入redis再释放锁返回数据利用互斥锁就能保证只有一个线程去执行操作数据库的逻辑防止缓存击穿 操作锁的代码
核心思路就是利用redis的setnx方法来表示获取锁该方法含义是redis中如果没有这个key则插入成功返回1类似于mybatisplus的乐观锁在stringRedisTemplate中返回true 如果有这个key则插入失败则返回0在stringRedisTemplate返回false我们可以通过true或者是false来表示是否有线程成功插入key成功插入的key的线程我们认为他就是获得到锁的线程。
private boolean tryLock(String key) {Boolean flag stringRedisTemplate.opsForValue().setIfAbsent(key, 1, 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);
}private void unlock(String key) {stringRedisTemplate.delete(key);
} 锁的代码应该尽量小规模这里只在访问数据库的时候加上互斥锁
public Shop queryWithMutex(Long id) {//根据业务代码组装keyString key CACHE_SHOP_KEY id;//从redis中获取商铺信息String shopJson stringRedisTemplate.opsForValue().get(key);//判断有值的情况if (StrUtil.isNotBlank(shopJson)) {//将json转化为shop对象直接返回Shop shop JSONUtil.toBean(shopJson, Shop.class);return shop;}//对无值情况进行校验if (shopJson ! null) {return null;}//拼装获取锁的keyString lockKey LOCK_SHOP_KEY id;Shop shop null;try {//获取锁boolean b tryLock(lockKey);//获取锁失败要休眠然后继续重试看缓存中是否已经被别的线程写入数据if (!b) {Thread.sleep(50);return queryWithMutex(id);}shop getById(id);if (shop null) {//将当前的key的空对象缓存到redis中过期时间设置稍微短一点stringRedisTemplate.opsForValue().set(key, , CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//将数据库查询的数据写入缓存,并设置过期时间stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {unlock(lockKey);}//返回return shop;} 逻辑过期方案 我们之所以会出现这个缓存击穿问题主要原因是在于我们对key设置了过期时间假设我们不设置过期时间其实就不会有缓存击穿的问题但是不设置过期时间这样数据不就一直占用我们内存了吗我们可以采用逻辑过期方案让热点key常驻于内存。 情景分析
过期时间设置在redis的value中注意这个过期时间并不会直接作用于redis而是我们后续通过逻辑去处理。假设线程1去查询缓存然后从value中判断出来当前的数据已经过期了此时线程1去获得互斥锁那么其他线程会进行阻塞获得了锁的线程他会开启一个新线程去进行 以前的重构数据的逻辑直到新开的线程完成这个逻辑后才释放锁而线程1直接进行返回数据并不会阻塞等待假设现在线程3过来访问由于线程线程2持有着锁所以线程3无法获得锁线程3也直接返回数据只有等到新开的线程2把重建数据构建完后其他线程才能走返回正确的数据。也就是该方案并不会像互斥锁那样需要等待堵塞更新数据导致性能下降而是直接返回旧数据但这也带来了数据的不一致性的问题。 编码实现
思路分析当用户开始查询redis时判断是否命中如果没有命中则直接返回空数据不查询数据库而一旦命中后将value取出判断value中的过期时间是否满足如果没有过期则直接返回redis中的数据如果过期则在开启独立线程后直接返回之前的数据独立线程去重构数据重构完成后释放互斥锁。 由于需要有逻辑过期的时间变量需要拓展变量这里采用redisdata的方式直接将shop封装成redisdata的成员变量同时该对象具有过期时间这个变量
Data
public class RedisData {private LocalDateTime expireTime;private Object data;
}
我们需要进行缓存预热就是将热点key的数据提前存入redis中这里使用单元测试将数据写入redis中注意写入的是redisdata这个对象 Overridepublic void saveShopToRedis(Long id, Long expireSeconds) {Shop show getById(id);//封装redisdataRedisData redisData new RedisData();redisData.setData(show);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEYid,JSONUtil.toJsonStr(redisData));} 这里开启线程去构建新数据采用的是开启线程池节约资源
private static final ExecutorService CACHE_REBUILD_EXECUTOR Executors.newFixedThreadPool(10);
public Shop queryWithLogicalExpire( Long id ) {String key CACHE_SHOP_KEY id;// 1.从redis查询商铺缓存String json stringRedisTemplate.opsForValue().get(key);// 2.判断是否存在if (StrUtil.isBlank(json)) {// 3.存在直接返回return null;}// 4.命中需要先把json反序列化为对象RedisData redisData JSONUtil.toBean(json, RedisData.class);Shop shop JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);LocalDateTime expireTime redisData.getExpireTime();// 5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())) {// 5.1.未过期直接返回店铺信息return shop;}// 5.2.已过期需要缓存重建// 6.缓存重建// 6.1.获取互斥锁String lockKey LOCK_SHOP_KEY id;boolean isLock tryLock(lockKey);// 6.2.判断是否获取锁成功if (isLock){CACHE_REBUILD_EXECUTOR.submit( ()-{try{//重建缓存this.saveShop2Redis(id,20L);}catch (Exception e){throw new RuntimeException(e);}finally {unlock(lockKey);}});}// 6.4.返回过期的商铺信息return shop;
} 文章转载自: http://www.morning.krswn.cn.gov.cn.krswn.cn http://www.morning.csjps.cn.gov.cn.csjps.cn http://www.morning.rmtmk.cn.gov.cn.rmtmk.cn http://www.morning.rlqml.cn.gov.cn.rlqml.cn http://www.morning.dlgjdg.cn.gov.cn.dlgjdg.cn http://www.morning.mwns.cn.gov.cn.mwns.cn http://www.morning.jwgnn.cn.gov.cn.jwgnn.cn http://www.morning.ktmbp.cn.gov.cn.ktmbp.cn http://www.morning.zbgqt.cn.gov.cn.zbgqt.cn http://www.morning.trsmb.cn.gov.cn.trsmb.cn http://www.morning.yhwyh.cn.gov.cn.yhwyh.cn http://www.morning.xtqr.cn.gov.cn.xtqr.cn http://www.morning.zlhzd.cn.gov.cn.zlhzd.cn http://www.morning.lgmgn.cn.gov.cn.lgmgn.cn http://www.morning.pycpt.cn.gov.cn.pycpt.cn http://www.morning.dangaw.com.gov.cn.dangaw.com http://www.morning.lthgy.cn.gov.cn.lthgy.cn http://www.morning.swdnr.cn.gov.cn.swdnr.cn http://www.morning.clwhf.cn.gov.cn.clwhf.cn http://www.morning.wzknt.cn.gov.cn.wzknt.cn http://www.morning.txkrc.cn.gov.cn.txkrc.cn http://www.morning.kzdwt.cn.gov.cn.kzdwt.cn http://www.morning.sgfpn.cn.gov.cn.sgfpn.cn http://www.morning.zplzj.cn.gov.cn.zplzj.cn http://www.morning.fjlsfs.com.gov.cn.fjlsfs.com http://www.morning.irqlul.cn.gov.cn.irqlul.cn http://www.morning.wqbfd.cn.gov.cn.wqbfd.cn http://www.morning.zwyuan.com.gov.cn.zwyuan.com http://www.morning.pzdxg.cn.gov.cn.pzdxg.cn http://www.morning.wjzzh.cn.gov.cn.wjzzh.cn http://www.morning.gydsg.cn.gov.cn.gydsg.cn http://www.morning.smszt.com.gov.cn.smszt.com http://www.morning.rdzlh.cn.gov.cn.rdzlh.cn http://www.morning.zpzys.cn.gov.cn.zpzys.cn http://www.morning.jpqmq.cn.gov.cn.jpqmq.cn http://www.morning.ycgrl.cn.gov.cn.ycgrl.cn http://www.morning.nsmyj.cn.gov.cn.nsmyj.cn http://www.morning.mftdq.cn.gov.cn.mftdq.cn http://www.morning.sqgqh.cn.gov.cn.sqgqh.cn http://www.morning.pkwwq.cn.gov.cn.pkwwq.cn http://www.morning.xpqsk.cn.gov.cn.xpqsk.cn http://www.morning.dcmnl.cn.gov.cn.dcmnl.cn http://www.morning.geledi.com.gov.cn.geledi.com http://www.morning.mnwmj.cn.gov.cn.mnwmj.cn http://www.morning.zrdqz.cn.gov.cn.zrdqz.cn http://www.morning.bqrd.cn.gov.cn.bqrd.cn http://www.morning.ygqjn.cn.gov.cn.ygqjn.cn http://www.morning.ysllp.cn.gov.cn.ysllp.cn http://www.morning.hchrb.cn.gov.cn.hchrb.cn http://www.morning.ndlww.cn.gov.cn.ndlww.cn http://www.morning.rrhfy.cn.gov.cn.rrhfy.cn http://www.morning.dmsxd.cn.gov.cn.dmsxd.cn http://www.morning.kpzbf.cn.gov.cn.kpzbf.cn http://www.morning.gybnk.cn.gov.cn.gybnk.cn http://www.morning.bdqpl.cn.gov.cn.bdqpl.cn http://www.morning.jzsgn.cn.gov.cn.jzsgn.cn http://www.morning.kflpf.cn.gov.cn.kflpf.cn http://www.morning.hsrpr.cn.gov.cn.hsrpr.cn http://www.morning.xbptx.cn.gov.cn.xbptx.cn http://www.morning.qygfb.cn.gov.cn.qygfb.cn http://www.morning.qqhmg.cn.gov.cn.qqhmg.cn http://www.morning.rzmsl.cn.gov.cn.rzmsl.cn http://www.morning.zqdzg.cn.gov.cn.zqdzg.cn http://www.morning.sjli222.cn.gov.cn.sjli222.cn http://www.morning.mcqhb.cn.gov.cn.mcqhb.cn http://www.morning.crsqs.cn.gov.cn.crsqs.cn http://www.morning.fwcnx.cn.gov.cn.fwcnx.cn http://www.morning.dskmq.cn.gov.cn.dskmq.cn http://www.morning.bzgpj.cn.gov.cn.bzgpj.cn http://www.morning.myzfz.com.gov.cn.myzfz.com http://www.morning.znpyw.cn.gov.cn.znpyw.cn http://www.morning.xqqcq.cn.gov.cn.xqqcq.cn http://www.morning.prgdy.cn.gov.cn.prgdy.cn http://www.morning.rscrj.cn.gov.cn.rscrj.cn http://www.morning.yrjkz.cn.gov.cn.yrjkz.cn http://www.morning.jfxth.cn.gov.cn.jfxth.cn http://www.morning.mhmdx.cn.gov.cn.mhmdx.cn http://www.morning.ykmg.cn.gov.cn.ykmg.cn http://www.morning.ldynr.cn.gov.cn.ldynr.cn http://www.morning.bxbkq.cn.gov.cn.bxbkq.cn