用好Java中的枚举真分布式锁之Zookeeper

用好Java中的枚举真分布式锁之Zookeeper
多线程下,想要保护数据,加锁的机制。

我们为了减少DB的压力,把库存预热到了KV,现在KV的库存是1。
服务A去Redis查询到库存发现是1,那说明我能抢到这个商品对不对,那我就准备减一了,但是还没减。
同时服务B也去拿发现也是1,那我也抢到了呀,那我也减。
C同理。
等所有的服务都判断完了,你发现诶,怎么变成-2了,超卖了呀,这下完了。
老公们是不是发现问题了,这就需要分布式锁的介入了,我会分三个章节去分别介绍分布式锁的三种实现方式(Zookeeper,Redis,MySQL),说出他们的优缺点,以及一般大厂的实践场景。

正文
  1. 正常线程进程同步的机制有哪些?
互斥:互斥的机制,保证同一时间只有一个线程可以操作共享资源 synchronized,Lock等。
临界值:让多线程串行话去访问资源
事件通知:通过事件的通知去保证大家都有序访问共享资源
信号量:多个任务同时访问,同时限制数量,比如发令枪CDL,Semaphore等
  1. 那分布式锁你了解过有哪些么?
分布式锁实现主要以Zookeeper(以下简称zk)、Redis、MySQL这三种为主。
  1. 那先跟我聊一下zk吧,你能说一下他常见的使用场景么?
服务注册与订阅(共用节点)
分布式通知(监听znode)
服务命名(znode特性)
数据订阅、发布(watcher)
分布式锁(临时节点)
  1. zk是啥?
他是个数据库,文件存储系统,并且有监听通知机制(观察者模式)
  1. 存文件系统,他存了什么?
节点

zk的节点类型有4大类

持久化节点(zk断开节点还在)

持久化顺序编号目录节点

临时目录节点(客户端断开后节点就删除了)

临时目录编号目录节点

节点名称都是唯一的。
  1. 节点怎么创建?
create /test laogong // 创建永久节点 

那临时节点呢?(临时节点就创建成功了,如果我断开这次链接,这个节点自然就消失了)

create -e /test laogong // 创建临时节点

如何创建顺序节点呢?

create -s /test // 创建顺序节点

临时顺序节点呢?

create -e -s /test  // 创建临时顺序节点
重点聊一下他在分布式锁中的实现。

zk就是基于节点去实现各种分布式锁的,zk节点有个唯一的特性,就是我们创建过这个节点了,你再创建zk是会报错的,那我们就利用一下他的唯一性去实现一下。

节点的唯一性

  1. 怎么实现呢?
    上面不是10个线程嘛?
    我们全部去创建,创建成功的第一个返回true他就可以继续下面的扣减库存操作,后续的节点访问就会全部报错,扣减失败,我们把它们丢一个队列去排队。

    只有第一个线程能扣减成功,其他的都失败了。
    zk加锁的实现

  2. 那怎么释放锁呢?你不释放后面的报错了就不重试了.
    删除节点咯,删了再通知其他的人过来加锁,依次类推。

    那简单,删除锁就释放掉了,Lock在finally里面unLock,现在我们在finally删除节点。

  3. 加锁我们知道创建节点就够了,但是你得实现一个阻塞的效果呀,那咋搞?
    死循环,递归不断去尝试,直到成功,一个伪装的阻塞效果。

  4. 怎么知道前面的老哥删除节点了嗯?
    监听节点的删除事件
    但是你发现你这样做的问题没?

    是的,会出现死锁。第一个仔加锁成功了,在执行代码的时候,机器宕机了,那节点是不是就不能删除了?创建临时节点就好了,客户端连接一断开,别的就可以监听到节点的变化了。

    监听机制也不好。

    你们可以看到,监听,是所有服务都去监听一个节点的,节点的释放也会通知所有的服务器,如果是900个服务器呢?
    这对服务器是很大的一个挑战,一个释放的消息,就好像一个牧羊犬进入了羊群,大家都四散而开,随时可能干掉机器,会占用服务资源,网络带宽等等。
    这就是羊群效应。
    临时顺序节点,可以顺利解决这个问题.
    之前说了全部监听一个节点问题很大,那我们就监听我们的前一个节点,因为是顺序的,很容易找到自己的前后。
    和之前监听一个永久节点的区别就在于,这里每个节点只监听了自己的前一个节点,释放当然也是一个个释放下去,就不会出现羊群效应了。

  5. 你能说说ZK在分布式锁中实践的一些缺点么?

Zk性能上可能并没有缓存服务那么高。
因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。
ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同步到所有的Follower机器上。

使用Zookeeper也有可能带来并发问题,只是并不常见而已。
由于网络抖动,客户端可ZK集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这时候其他客户端就可以获取到分布式锁了。
就可能产生并发问题了,这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,Curator客户端支持多种重试策略。
多次重试之后还不行的话才会删除临时节点。
Tip:所以,选择一个合适的重试策略也比较重要,要在锁的粒度和并发之间找一个平衡。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值