一、ZooKeeper 分布式锁机制
当有多个客户端要获取ZK 里中的一把锁,即ZK 上的一个节点。
假设客户端 A 抢先一步,对 ZK 发起了加分布式锁的请求,这个加锁请求是用到了 ZK 中的一个特殊的概念,叫做“临时顺序节点”。简单来说,就是直接在锁节点下,创建一个顺序节点,这个顺序节点有 ZK 内部自行维护的一个节点序号。此时顺序节点的第一个客户端就加锁成功了。
后面进来的客户端依次一个接一个的临时顺序节点。如果如自己不是第一个节点,就对自己上一个节点加监听器。ZK 天然就可以实现对某个节点的监听。
只要上一个节点释放锁,自己就排到前面去了,相当于是一个排队机制。客户端 A 加锁之后,可能处理了一些代码逻辑,然后就会释放锁,就是把自己在 ZK 里创建的那个顺序节点给删除。删除了那个节点之后,ZK 会负责通知监听这个节点的监听器。被通知的客户端 B 会重新尝试去获取锁。
使用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,ZK 感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。
二、分布式锁高并发优化实践
分布式锁的缺陷:对同一个key就行操作时,会基于分布式锁串行化处理,导致没法同时处理同一个key的大量请求。
优化方案:分段加锁
把数据分成很多个段,每个段是一个单独的锁,所以多个线程过来并发修改数据的时候,可以并发的修改不同段的数据。不至于说,同一时间只能有一个线程独占修改 ConcurrentHashMap 中的数据。
当然这样优化也会有不足之处:
首先,你得对一个数据分段存储,一个库存字段本来好好的,现在要分为 20 个库存字段。
其次,你在每次处理库存的时候,还得自己写随机算法,随机挑选一个分段来处理。
最后,如果某个分段中的数据不足了,你还得自动切换到下一个分段数据去处理。
网友评论