当前位置:   article > 正文

zookeeper实现分布式锁的原理及具体使用案例

zookeeper实现分布式锁的原理及具体使用案例

zookeeper跟redis一样,也是基于内存的。

官网:

http://zookeeper.apache.org/

zookeeper是分布式系统的协调服务,提供配置管理、分布式协同、命名的中心化服务以及服务注册发现等。

zookeeper分布式锁的实现原理:

zookeeper实现分布式锁采用其提供的有序临时节点+监听来实现。临时节点只要客户端断开连接就会被删除,正好可以利用这一特性实现锁。

zookeeper是由java语言开发的。

zookeeper中的节点类型:

节点就是用于存储数据的,在zookeeper中,节点是类似于文件系统的目录的结构。

①永久节点。会进行持久化,重启不会丢失。

②临时节点。存储在内存中,不会持久化,重启服务或断开连接数据会丢失。

节点中存储的数据可以进行排序。

当节点中的数据有更新或是节点被删除时,会触发zookeeper的通知机制告知客户端,因为zookeeper一直在监听所有的节点。

领红包具体案例:

【具体业务逻辑是:先查询下数据库,判断用户的红包数据是否为空,是则插入红包数据,否则不让插入】

①引入zkclient依赖:

  1. <!--zookeeper客户端zkclient-->
  2. <!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
  3. <dependency>
  4. <groupId>com.101tec</groupId>
  5. <artifactId>zkclient</artifactId>
  6. <version>0.11</version>
  7. </dependency>

②代码实现:

接口:

  1. package com.zhangxueliang.demo.springbootdemo.zookeeperLock;
  2. public interface ZookeeperLock {
  3. //加锁
  4. void lock();
  5. //解锁
  6. void unlock();
  7. }

 抽象类:

  1. package com.zhangxueliang.demo.springbootdemo.zookeeperLock;
  2. import org.I0Itec.zkclient.ZkClient;
  3. import java.util.concurrent.CountDownLatch;
  4. /**
  5. * @ProjectName springbootdemo_src
  6. * @ClassName AbstractZookeeperLock
  7. * @Desicription tryLock和waitLock方法使用到了模板方法设计模式
  8. * @Author Zhang Xueliang
  9. * @Date 2020/1/13 14:19
  10. * @Version 1.0
  11. **/
  12. public abstract class AbstractZookeeperLock implements ZookeeperLock {
  13. protected String lock;
  14. protected CountDownLatch countDownLatch;//门闩(倒计数器)
  15. protected String zk_address = "127.0.0.1:2181";
  16. protected ZkClient zkClient = new ZkClient(zk_address);
  17. /**
  18. * 加锁
  19. */
  20. @Override
  21. public final void lock() {
  22. //尝试获取锁
  23. if (tryLock()){
  24. //已经拿到锁
  25. System.out.println("获取锁成功。。。");
  26. }else {
  27. //尝试获取锁未成功,等待获取锁,阻塞,如果此处已经不阻塞了,那么可以继续往下执行代码
  28. waitLock();
  29. //上面的阻塞结束了,那么我可以继续获取锁,递归一下
  30. }
  31. }
  32. /**
  33. * 释放锁
  34. */
  35. @Override
  36. public final void unlock() {
  37. //关闭连接就解锁了
  38. if(zkClient!=null){
  39. zkClient.close();//此处也可以使用zkClient.delete(临时节点)来实现解锁
  40. System.out.println("解锁成功。。。");
  41. }
  42. }
  43. //尝试获取锁
  44. protected abstract boolean tryLock();
  45. //等待获取锁
  46. protected abstract void waitLock();
  47. }

锁实现类:

  1. package com.zhangxueliang.demo.springbootdemo.zookeeperLock;
  2. import org.I0Itec.zkclient.IZkDataListener;
  3. import java.util.concurrent.CountDownLatch;
  4. /**
  5. * @ProjectName springbootdemo_src
  6. * @ClassName ZookeeperDistributedLock
  7. * @Desicription TODO
  8. * @Author Zhang Xueliang
  9. * @Date 2020/1/13 14:32
  10. * @Version 1.0
  11. **/
  12. public class ZookeeperDistributedLock extends AbstractZookeeperLock {
  13. public ZookeeperDistributedLock(String lockName){
  14. lock=lockName;
  15. }
  16. /**
  17. * 尝试获取锁
  18. * @return
  19. */
  20. @Override
  21. protected boolean tryLock() {
  22. try {
  23. //创建一个临时节点
  24. zkClient.createEphemeral(lock);
  25. return true;
  26. }catch (Exception e){
  27. return false;
  28. }
  29. }
  30. /**
  31. * 等待获取锁
  32. */
  33. @Override
  34. protected void waitLock() {
  35. //如果已经有线程创建了临时节点,那么其他线程就只能等待,不能再创建该临时节点
  36. //此时我就监听(就是订阅数据的改变)你这个临时节点,如果该节点被删除了我就等待结束,就又可以创建临时节点
  37. //1.订阅数据改变,就是指定监听参数中所指定的那个节点
  38. IZkDataListener listener = new IZkDataListener() {
  39. //监听改变
  40. @Override
  41. public void handleDataChange(String s, Object o) throws Exception {
  42. }
  43. //监听删除
  44. @Override
  45. public void handleDataDeleted(String s) throws Exception {
  46. if (countDownLatch!=null){
  47. countDownLatch.countDown();
  48. }
  49. }
  50. };
  51. //2.判断锁的节点是否存在
  52. if (zkClient.exists(lock)){
  53. countDownLatch = new CountDownLatch(1);
  54. try {
  55. //当计数器从1变成0之后,等待就会结束了
  56. countDownLatch.await();
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. //3.取消订阅
  62. zkClient.unsubscribeDataChanges(lock,listener);
  63. }
  64. }

zookeeper分布式锁代码测试:

  1. //测试
  2. public static void main(String[] args) {
  3. ZookeeperDistributedLock zookeeperDistributedLock = new ZookeeperDistributedLock("/addRedPacket");//一定要带/ 不然节点添加不成功
  4. try{
  5. zookeeperDistributedLock.lock();
  6. //TODO 具体要锁住的业务代码
  7. //查询用户是否已经领过红包
  8. //添加红包给用户
  9. }finally {
  10. zookeeperDistributedLock.unlock();
  11. }
  12. }

测试时需要将zoo_sample.cfg配置文件中的zookeeper最大连接数调大些:

maxClientCnxns=1000 #默认60

启动两个端口:

配置nginx.conf实现负载均衡

使用jmeter测试时访问的是nginx的80端口:

使用jmeter模拟高并发场景:

相关参数配置--

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号