vlambda博客
学习文章列表

聊聊Redis那些事(下篇)

五、Redis分布式锁

概念:对于操作共享的资源时,需要使用Redis锁进行控制(如不是分布式或集群系统 可用JVM级别锁实现)

Redis分布式锁基础实现(有问题的)
// 分布式锁的keyString lock = "lock";// 只有当Redis中没有这个key 才能设置成功 并设置超时时间// 注意超时时间需要根据实际业务代码执行时间决定Boolean getLock = stringRedisTemplate.opsForValue().setIfAbsent(lock,"lock",30,TimeUnit.SECOND);
if(!getLock){ // 当前线程没有拿到锁 执行没有拿到锁的逻辑 return false}
// 防止业务代码遇异常而不释放锁try{ // 拿到了锁 进行业务操作 ... ...}finally{ stringRedisTempLate.delete(lock);}

// 上面的代码是有问题的// 思考一下 一旦设置了锁的超时时间 在锁因为到期时间而自动删除时 那么再delete的时候删除的key一定是自己加的吗?

###############################################################################
String lock = "lock";// 在上面代码的基础上 我们对于每个线程都生成一个唯一的值 并且把这个值放到Redis的value中去String value = UUID.randomUUID().toString(); , // Boolean getLock = stringRedisTemplate.opsForValue().setIfAbsent(lock,value,30,TimeUnit.SECOND); ... ...}finally{ // 保证当前线程加的锁当前线程删 if(value.equals(stringRedisTemplate.opsForValue().get(lock))){ stringRedisTempLate.delete(lock); }
}

但是上面的代码写成这样还是有问题的 想象一下 如果锁因为过期时间而自动到期 而业务代码未执行完毕 这时候其他线程进来了 还是会产生一定的问题


锁续命Redisson

// 分布式锁的keyString lock = "lock";// 只有当Redis中没有这个key 才能设置成功 并设置超时时间// 注意超时时间需要根据实际业务代码执行时间决定String value = UUID.randomUUID().toString(); , // Boolean getLock = stringRedisTemplate.opsForValue().setIfAbsent(lock,value,30,TimeUnit.SECOND);// 拿到一把锁RLock rlock = Redisson.getLock(lock);if(!getLock){ // 当前线程没有拿到锁 执行没有拿到锁的逻辑 return false}// 锁续命功能// 默认30s超时rlock.lock(); // 防止业务代码遇异常而不释放锁try{ // 拿到了锁 进行业务操作 ... ...}finally{ //解锁 rlock.unlock(); // 保证当前线程加的锁当前线程删 if(value.equals(stringRedisTemplate.opsForValue().get(lock))){ stringRedisTempLate.delete(lock); }}



锁续命相当于还是去Redis设置一个锁 并且开辟一个子线程看当前线程是否还持有这把锁 如果业务代码没执行完而因为锁的过期时间而导致锁过期 那么锁会自动续命(延长过期时间)


Redisson利用大量的lua脚本保证多条命令执行的原子性



六、Lua脚本与管道

优点:

  • 操作具有原子性(事务功能)(管道不具备事务功能)

  • 节省网络开销


缺点:

  • 不要再Lua脚本出现耗时的运算 这会导致Redis阻塞(管道不会阻塞)



七、RedLock

用来解决主节点加锁后未同步到从节点时 主节点挂掉 从节点变主节点后 产生的二次加锁的问题

RedLock 把锁发给了半数以上的从节点来保证一致性 但是会带来性能问题





八、Redis相关问题


缓存穿透

缓存穿透指查询了一个数据库和Redis都不存在的key


解决办法:

  • 缓存查询结果(无论是否有数据)


缓存雪崩

大量的key在同一时间失效


解决办法:

  • 设置缓存过期时间时增加基础时间+随机策略

  • 接口限流


过期键清除策略

1.惰性删除: 当读/写一个已经过期的key时候 会删除这个key

2.主动删除: Redis六哦那个淘汰策略主动删除key