微服务_缓存与分布式锁

 哪些数据适合放入缓存?
        即时性,数据一致性要求不高的
        访问量大且更新频率不高的数据
    
高并发下缓存失效问题
    缓存穿透
        只查询一个不存在的数据,由于缓存不命中,将去查询数据库,但是数据库也没有记录
        导致每次都要到数据库查询,是去了缓存的意义
        
        风险:
            利用不存在的数据进行攻击,数据库瞬时压力增大,最终导致崩溃
        解决
            将null结果缓存,并加入短暂过期时间
    
    缓存雪崩
        缓存雪崩是指我们设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求
        全部转发到数据库,导致数据库瞬时压力过大
        
        解决
            在原有的失效时间的基础上加一个随机值,这样每一个缓存的过期时间的重复率就会降低
    
    缓存击穿
        某个缓存数据是一个热点数据,如果这个key在大量请求同时进来前正好失效
        请求全部转发到数据库,导致数据库瞬时压力过大
        
        解决
            加锁,大量并发只让一个查询,其他人等到,查到以后再释放锁,其他人获取到锁,
            先查缓存,就会有数据,不用去数据库查询
        
分布式锁
    本地锁,只能锁住当前服务,想要锁住所有服务,必须使用分布式锁
    
    执行逻辑:
        加锁成功,给锁设置过期时间,而且加锁与设置过期时间必须是一个原子操作,执行业务:
            执行正常完成,删除分布式锁
            执行出现异常,删除分布式锁
            程序异常中断(断电),锁到期自动删除
        
        加锁失败,采用自旋的方式(可以休眠一段时间,比如100ms),继续尝试加锁
                
        删除锁问题
            1.由于业务执行的时间很长,锁自动过期了,直接删除锁,有可能把别人正在持有的锁删除了
                解决:
                占锁的时候,将value设置为UUID,删除的时候匹配value才删除
                
            2.如果value匹配正确,正要删除锁的时候,锁过期了,别人也设置了新的值
              那么我们删除的是别人的锁
              
                解决:
                删除锁必须保证原子性,使用redis+Lua脚本完成
                String script = "if redis.call('get',KEYS[1]) == ARVG[1] then return redis.call('del',KEYS[1]) else return 0 end";
                redisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class),
                                      Arrays.asList("lock"),
                                      uuid);

分布式锁核心:加锁和解锁都保证原子性

posted @ 2022-07-22 14:28  Chen_Ken  阅读(104)  评论(0)    收藏  举报