网站做支付系统,太仓网页制作招聘,珠海移动app开发公司,企业网站群建设方案缓存击穿(热点key)#xff1a; 部分key(被高并发访问且缓存重建业务复杂的)失效,无数请求会直接到数据库#xff0c;造成巨大压力
1.互斥锁#xff1a;可以保证强一致性 线程一#xff1a;未命中之后#xff0c;获取互斥锁#xff0c;再查询数据库重建缓存#xff0c;写…缓存击穿(热点key) 部分key(被高并发访问且缓存重建业务复杂的)失效,无数请求会直接到数据库造成巨大压力
1.互斥锁可以保证强一致性 线程一未命中之后获取互斥锁再查询数据库重建缓存写入缓存释放锁 线程二查询未命中未获得锁(已由线程一获得)等待一会缓存命中
互斥锁实现方式redis中setnx key value:改变对应key的value,仅当value不存在时执行以此来实现互斥锁防止出现锁得不到释放设置有效期
public Shop queryWithMutex(Long id) throws InterruptedException {Shop shop;//实现互斥锁,解决缓存击穿String keyCACHE_SHOP_KEYid;//1.从redis查询商铺缓存String shopJsonstringRedisTemplate.opsForValue().get(key);//2.判断是否存在,isNotBlank()也为falseif(StrUtil.isNotBlank(shopJson)){//3.存在返回商铺对象return JSONUtil.toBean(shopJson,Shop.class);}//判断命中的是否为空值if(shopJson ! null shopJson.isEmpty()){return null;}//4.实现缓存重建String lockKeyLOCK_SHOP_KEYid;//4.1.获取互斥锁boolean isLocktryLock(lockKey);//4.2.判断互斥锁是否成功if(!isLock){//4.3.未成功,等待Thread.sleep(50);//递归shopqueryWithMutex(id);}else{//4.4.成功,从mysql数据库中查询shopgetById(id);//5.判断是否存在if(shopnull){//缓存空值处理缓存穿透stringRedisTemplate.opsForValue().set(key,,CACHE_NULL_TTL,TimeUnit.MINUTES);return null;}//6.存在向redis中缓存店铺数据stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),LOGIN_USER_TTL, TimeUnit.MINUTES);//7.释放互斥锁unlock(lockKey);}//8.返回return shop;}
2.逻辑过期 不存TTL,添加上逻辑过期时间判断逻辑上有没有过期以此来更新数据 线程一查询缓存逻辑已过期获取互斥锁开启新线程返回过期数据 新线程查询数据库并重建缓存重置逻辑过期时间释放锁 线程二查询未命中未获得锁(已由线程一获得)返回过期数据 private boolean tryLock(String key){//尝试获得互斥锁Boolean flagstringRedisTemplate.opsForValue().setIfAbsent(key,1,LOCK_SHOP_TTL,TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);//通过工具类将其转化为基本类型}private void unlock(String key){//删除锁stringRedisTemplate.delete(key);}
实现互斥锁相关的方法
//线程池有10个线程private static final ExecutorService CACHE_REBUILD_EXECUTOR Executors.newFixedThreadPool(10);
创建线程池
public Shop queryWithLogicalExpire(Long id) {//实现逻辑过期解决缓存击穿(不存在缓存穿透问题)String keyCACHE_SHOP_KEYid;String lockKeyLOCK_SHOP_KEYid;//1.从redis查询商铺缓存String shopJsonstringRedisTemplate.opsForValue().get(key);//2.判断是否存在if(StrUtil.isBlank(shopJson)){//3.不存在返回nullreturn null;}//4.存在判断是否过期//将Json反序列化成RedisDate对象RedisData redisDataJSONUtil.toBean(shopJson,RedisData.class);Shop shopJSONUtil.toBean((JSONObject)redisData.getData(),Shop.class);//5.过期if(LocalDateTime.now().isAfter(redisData.getExpireTime())){//6.缓存重建//6.1.获取互斥锁boolean isLocktryLock(lockKey);//6.2.获取成功if(isLock){//开启新线程CACHE_REBUILD_EXECUTOR.submit(()-{try {saveShopToRedis(id, 20L);}catch(Exception e){throw new RuntimeException(e);}finally {//释放锁unlock(lockKey);}});}//6.3.获取失败return shop;}return shop;}
逻辑删除相关方法