Sven

分布式锁


redis 实现

setnx 命令

Setnx(SET if Not eXists): 在指定的 key 不存在时,为 key 设置指定的值; 设置成功,返回 1。 设置失败,返回 0;

分布式锁

  • 两个服务A,B; 通过Nginx做负载均衡到服务, 两个服务对临界资源进行操作的时候会出现并发问题;
  • 所以通过引入Redis做分布式锁;

V1: 通过 Redis 做分布式锁

  • 存在的问题
    • 假设服务A在阶段4发生了异常, 程序炸了, 那锁就得不到释放, 就锁死了;
  • 解决方案
    • 增加key的过期时间

V2: 增加key的过期时间

  • 存在的问题

    • 会把别人的锁释放掉

  • 解决方案: 使用UUID做服务的唯一标识;

V3: 获取锁时增加唯一UUID,防止释放别人的锁

  • 存在的问题
    • 删除锁的时候不能保证原子性, 获取lock的value和删除锁不是原子操作, 可能多个线程获取了相同的UUID-B, 然后一顿解锁,,,,,把人家C的锁给删除了, 就完犊子了!

V4: 使用lua, (或者redis事务), 保证删除(释放锁)操作的原子性

  • Spring-Data-Redis 支持使用lua脚本 image-20220617213322637

V5: 框架 Redisson

  • redis官方推荐的redis分布式锁方案

  • redisson源码用lua脚本保证原子性

  • 集群环境下,依次从各个节点获取锁,半数以上节点获取成功才真正获取锁成功,否则释放已经获取的锁

  • 单redis,两个服务访问临界资源的环境下,吞吐量不到700


2点注意

  • redisson 方案性能不好;

  • 业务逻辑操作的临界资源都是在redis中存放的前提下, 在lua里写业务逻辑,用Java调,保证原子性,性能很高,单redis,两个服务访问临界资源的环境下, 这种方式吞吐量测试有2000, 比直接用redisson加锁高3倍; image-20220617211820291

On this page