redis分布式锁的处理
缓存击穿
问题1:当数据没有缓存的时候,正好有很多个请求一起去访问数据。
解决方法1:
利用setnx增加分布式锁
同时只有一个线程能拿到锁,其他线程自旋等待
问题2:如果某个线程拿到锁很长时间没处理完,其他线程会一直等待。
问题3:如果设置锁的超时时间,在释放锁del的时候,可能删除的是别人所持到的锁。
解决方法,得到锁的线程只会释放自己的锁 每个线程生成一个一个随机token,释放锁的时候加以验证
缓存穿透
查询一个不存在于缓存和数据库的数据,永远不会加载缓存,会反复查询数据库,增加io压力
@Override public SkuInfo getSkuById(String skuId) { //redis缓存和缓存锁应该为不同的节点,这里简化为在同一个节点上 Jedis jedis = redisUtil.getJedis(); SkuInfo skuInfo = null; //查询redis缓存 String key = "sku:" + skuId + ":info"; String val = jedis.get(key); //此数据在数据库中也没有,直接返回空值 //避免缓存穿透,即数据库和缓存中都没有值,却不断的去查询,导致宕机 if ("empty".equals(val)) { return skuInfo; } if (StringUtils.isBlank(val)) {//没有命中缓存,查询数据库 //申请缓存锁 String OK = jedis.set("sku:" + skuId + ":lock", "1", "nx", "px", 3000); if ("OK".equals(OK)) {//拿到缓存锁 //查询数db skuInfo = getSkuByIdFormDb(skuId); if (skuInfo != null) { //同步缓存 jedis.set(key, JSON.toJSONString(skuInfo)); } else { //当其他线程再执行时,通知同伴,数据库中没有 jedis.setex("sku:" + skuId + ":info", 10, "empty"); } //归还锁 jedis.del("sku:" + skuId + ":lock"); } else {//没有拿到缓存锁 //自旋 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } getSkuById(skuId); } } else {//查询的数据在缓存中 skuInfo = JSON.parseObject(val, SkuInfo.class); } return skuInfo; }