原文

笔记

Redisson框架实现Redis分布式锁的底层原理

【读书笔记】分布式锁
【读书笔记】分布式锁
如果该客户端面对的是一个Redis Cluster集群,他首先会根据Hash节点选择一台机器。仅仅只是选择一台机器!然后发送一段Lua脚本到Redis上,那段Lua脚本如下所示:
【读书笔记】分布式锁

  • KEYS[1]代表的是你加锁的那个Key
  • ARGV[1]代表的就是锁Key的默认生存时间,默认30秒。
  • ARGV[2]代表的是加锁的客户端的ID,类似于下面这样的:8743c9c0-0795-4907-87fd-6c719a6b4586:1。

上述Redis分布式锁的缺点

  • 如果你对某个Redis Master实例,写入了myLock这种锁Key的Value,此时会异步复制给对应的Master Slave实例。但是这个过程中一旦发生Redis Master宕机,主备切换,Redis Slave变为了Redis Master。会导致客户端2尝试加锁时,在新的Redis Master上完成加锁,客户端1也以为自己成功加锁。此时就会导致多个客户端对一个分布式锁完成了加锁。这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。

Curator框架实现ZooKeeper分布式锁的底层原理

【读书笔记】分布式锁
【读书笔记】分布式锁

  • 加锁请求是用到了ZK中的一个特殊的概念,叫做“临时顺序节点”。
  • 每个客户端创建完一个顺序节点,会走一个关键性的判断:这个集合里创建的顺序节点,是否排在首位?如果是,加锁成功。反之,加锁失败,此时该客户端会通过ZK的API对它的顺序节点的上一个顺序节点加一个监听器。ZK天然就可以实现对某个节点的监听。
  • 释放锁就是把自己在ZK里创建的那个顺序节点删除,此时,ZK会负责通知监听这个节点的监听器。
  • 用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,ZK感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。

应用场景举例

电商库存超卖

【读书笔记】分布式锁

解决方案

【读书笔记】分布式锁

  • 其他方案:悲观锁,分布式锁,乐观锁,队列串行化,异步队列分散,Redis原子操作,等等

优化方案

  • 问题:分布式锁一旦加了之后,对同一个商品的下单请求,会导致所有客户端都必须对同一个商品的库存锁Key进行加锁。导致对同一个商品的下单请求,就必须串行化,一个接一个的处理,没法同时处理同一个商品的大量下单的请求。
  • 相信很多人看过Java里的Concurrent Hash Map的源码和底层原理,应该知道里面的核心思路,就是分段加锁
  • 分段CAS操作,失败则自动迁移到下一个分段进行CAS
    【读书笔记】分布式锁
  • 假如现在iPhone有1000个库存,完全可以给拆成20个库存段。在Redis之类的地方放20个库存Key。总之,就是把你的1000件库存给他拆开,每个库存段是50件库存,比如stock_01对应50件库存,stock_02对应50件库存。接着,每秒1000个请求过来了!此时可以自己写一个简单的随机算法,每个请求都是随机在20个分段库存里,选择一个进行加锁。然后在业务逻辑里面,就对数据库或者是Redis中的那个分段库存进行操作即可,包括查库存→判断库存是否充足→扣减库存。
  • 注意:一旦对某个数据做了分段处理之后,有一个坑大家一定要注意:就是如果某个下单请求,咔嚓加锁,然后发现这个分段库存里的库存不足了。这时你得自动释放锁,然后立马换下一个分段库存,再次尝试加锁后尝试处理。

相关文章: