本地缓存问题:每个微服务都要有缓存服务、数据更新时只更新自己的缓存,造成缓存数据不一致
解决方案:分布式缓存,微服务共用 缓存中间件
分布式锁
分布式项目时,但本地锁只能锁住当前服务,需要分布式锁
redis分布式锁的原理:setnx,同一时刻只能设置成功一个
前提,锁的key是一定的,value可以变
没获取到锁阻塞或者sleep一会
设置好了锁,玩意服务出现宕机,没有执行删除锁逻辑,这就造成了死锁
解决:设置过期时间
业务还没执行完锁就过期了,别人拿到锁,自己执行完去删了别人的锁
解决:锁续期(redisson有看门狗),。删锁的时候明确是自己的锁。如uuid
判断uuid对了,但是将要删除的时候锁过期了,别人设置了新值,那删除了别人的锁
解决:删除锁必须保证原子性(保证判断和删锁是原子的)。使用redis+Lua脚本完成,脚本是原子的
if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end;
stringRedisTemplate.execute(
new DefaultRedisScript<Long返回值类型>(script脚本支付非常, Long.class返回值类型),
Arrays.asList("lock")键key的集合,
lockValue);
http://redis.cn/commands/set.html
最终代码:
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
String uuid = UUID.randomUUID().toString();
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
Boolean lock = ops.setIfAbsent("lock", uuid,500, TimeUnit.SECONDS);
if (lock) {
Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
String lockValue = ops.get("lock");
String script = "if redis.call("get",KEYS[1]) == ARGV[1] then
" +
" return redis.call("del",KEYS[1])
" +
"else
" +
" return 0
" +
"end";
stringRedisTemplate.execute(
new DefaultRedisScript<Long>(script, Long.class),
Arrays.asList("lock"),
lockValue);
return categoriesDb;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 睡眠0.1s后,重新调用//自旋
return getCatalogJsonDbWithRedisLock();
}
}
————————————————