redis分布式锁案例

1.缓存在高并发和安全压力下的一些问题

  缓存击穿:

          是某一个热点key在高并发访问的情况下,突然失效,导致大量的并发打进mysql数据库的情况

  缓存穿透: 

          是利用redis和mysql的机制(redis缓存一旦不存在,就访问mysql),直接绕过缓存访问mysql,而制造的db请求压力

一般在代码中防止该现象的发生

解决:// 为了防止缓存穿透将,null或者空字符串值设置给redis

  缓存雪崩:

         缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,导致的db崩溃

解决:设置不同的缓存失效时间

2.如何解决缓存击穿的问题

穿透:利用不存在的key去攻击mysql数据库

雪崩:缓存中的很多key失效,导致数据库负载过重宕机

击穿:在正常的访问情况下,如果缓存失效,如果保护mysql,重启缓存的过程

使用redis数据库的分布式锁,解决mysql的访问压力问题

第一种分布式锁:redis自带一个分布式锁,set px  nx  

redis分布式锁案例:

    @Override
    public  Food  getFoodById(String id) {
        Food  food= new Food  ();
        // 链接缓存
        Jedis jedis = redisUtil.getJedis();
        // 查询缓存(缓存到redis的key设计是:food:id:info)
        String foodKey = "food:"+id+":info";
        String foodJson = jedis.get(foodKey);

        if(StringUtils.isNotBlank(skuJson)){
            System.out.println(Thread.currentThread().getName()+"从缓存中获取数据");

            food= JSON.parseObject(foodJson, Food.class);
        }else{
            // 如果缓存中没有,查询mysql
            System.out.println("发现缓存中没有,申请缓存的分布式锁:"+"food:" + id+ ":lock");

            // 设置分布式锁
            String token = UUID.randomUUID().toString();
            String OK = jedis.set("food:" + id+ ":lock", token, "nx", "px", 10*1000);// 拿到锁的线程有10秒的过期时间
            if(StringUtils.isNotBlank(OK)&&OK.equals("OK")){
                // 设置成功,有权在10秒的过期时间内访问数据库
                System.out.println(Thread.currentThread().getName()+"有权在10秒的过期时间内访问数据库:"+"food:" + id+ ":lock");

                food=  getFoodByIdFromDb(id);//调用查询方法

                if(food!=null){
                    // mysql查询结果存入redis
                    jedis.set("food:"+id+":info",JSON.toJSONString(food));
                }else{
                    // 数据库中不存在该数据
                    // 为了防止缓存穿透将,null或者空字符串值设置给redis
                    jedis.setex("food:"+id+":info",60*3,JSON.toJSONString(""));
                }

                // 在访问mysql后,将mysql的分布锁释放
                System.out.println(Thread.currentThread().getName()+"使用完毕,将锁归还:"+"food:" + id+ ":lock");
                String lockToken = jedis.get("food:" + id+ ":lock");
                if(StringUtils.isNotBlank(lockToken)&&lockToken.equals(token)){
                    jedis.del("food:" + id+ ":lock");// 用token确认删除的是自己的数据的锁
                }
            }else{
                // 设置失败,自旋(该线程在睡眠几秒后,重新尝试访问本方法)
                System.out.println(Thread.currentThread().getName()+"没有拿到锁,开始自旋");

                return getFoodById(id);
            }
        }
        jedis.close();
        return food;
    }

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值