微服务_缓存与分布式锁
哪些数据适合放入缓存?
即时性,数据一致性要求不高的
访问量大且更新频率不高的数据
高并发下缓存失效问题
缓存穿透
只查询一个不存在的数据,由于缓存不命中,将去查询数据库,但是数据库也没有记录
导致每次都要到数据库查询,是去了缓存的意义
风险:
利用不存在的数据进行攻击,数据库瞬时压力增大,最终导致崩溃
解决
将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);
分布式锁核心:加锁和解锁都保证原子性

浙公网安备 33010602011771号