ZooKeeper实现分布式锁

Zookeeper实现分布式锁 如何用Zookeeper实现分布式锁? 在学习分布式锁之前,需要首先了解一下Zookeeper的[临时顺序节点]。 什么是临时顺序节点? 让我们来回顾一下Zookeeper节点的概念: Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode。 Znode分为四种类型: 1.持久节点 (PERSISTENT) 默认的节点类型。创建节点的客户端与zook... 阅读详情

共享锁在同一个进程中很容易实现,但是在跨进程或者在不同 Server 之间就不好实现了。Zookeeper 却很容易实现这个功能,实现方式也是需要获得锁的 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,然后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是不是就是自己创建的目录节点,如果正是自己创建的,那么它就获得了这个锁,如果不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到自己创建的节点是列表中最小编号的目录节点,从而获得锁,释放锁很简单,只要删除前面它自己所创建的目录节点就行了。

这里写图片描述
图 4. Zookeeper 实现 Locks 的流程图

实现原理的另外一种描述:
  • 客户端调用create()方法创建名为“locknode/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。
  • 客户端调用getChildren(“locknode”)方法来获取所有已经创建的子节点,同时在这个节点上注册上子节点变更通知的Watcher。
  • 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,那么就认为这个客户端获得了锁。
  • 如果在步骤3中发现自己并非是所有子节点中最小的,说明自己还没有获取到锁,就开始等待,直到下次子节点变更通知的时候,再进行子节点的获取,判断是否获取锁。
  • 释放锁的过程相对比较简单,就是删除自己创建的那个子节点即可。
问题所在

上面这个分布式锁的实现中,大体能够满足了一般的分布式集群竞争锁的需求。这里说的一般性场景是指集群规模不大,一般在10台机器以内。

不过,细想上面的实现逻辑,我们很容易会发现一个问题,步骤4,“即获取所有的子点,判断自己创建的节点是否已经是序号最小的节点”,这个过程,在整个分布式锁的竞争过程中,大量重复运行,并且绝大多数的运行结果都是判断出自己并非是序号最小的节点,从而继续等待下一次通知——这个显然看起来不怎么科学。客户端无端的接受到过多的和自己不相关的事件通知,这如果在集群规模大的时候,会对Server造成很大的性能影响,并且如果一旦同一时间有多个节点的客户端断开连接,这个时候,服务器就会像其余客户端发送大量的事件通知——这就是所谓的羊群效应。而这个问题的根源在于,没有找准客户端真正的关注点。

我们再来回顾一下上面的分布式锁竞争过程,它的核心逻辑在于:判断自己是否是所有节点中序号最小的。于是,很容易可以联想的到的是,每个节点的创建者只需要关注比自己序号小的那个节点。

改进后的分布式锁实现

下面是改进后的分布式锁实现,和之前的实现方式唯一不同之处在于,这里设计成每个锁竞争者,只需要关注”locknode”节点下序号比自己小的那个节点是否存在即可。实现如下:

  • 客户端调用create()方法创建名为“locknode/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。
  • 客户端调用getChildren(“locknode”)方法来获取所有已经创建的子节点,注意,这里不注册任何Watcher。
  • 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点序号最小,那么就认为这个客户端获得了锁。
  • 如果在步骤3中发现自己并非所有子节点中最小的,说明自己还没有获取到锁。此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时注册事件监听。
  • 之后当这个被关注的节点被移除了,客户端会收到相应的通知。这个时候客户端需要再次调用getChildren(“locknode”)方法来获取所有已经创建的子节点,确保自己确实是最小的节点了,然后进入步骤3。

下面是改进后的一种实现:

public class DistributedLock implements Watcher {
    private static final String hostPort = "localhost:2181";
    private ZooKeeper zk = null;
    private String root;
    private Object mutex = null;

    public DistributedLock(String root) {
        this.root = root;
        try {
            this.zk = new ZooKeeper(hostPort, 10 * 1000, this);
            Stat stat = zk.exists(root, true);
            mutex = new Date();
            if (null == stat) {
                zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {
        //释放锁的时候会删除临时节点,所以此处只监听删除节点的事件,以此减少客户端线程被notify的次数。
        if (event.getType().equals(Event.EventType.NodeDeleted)) {
            System.out.println(Thread.currentThread().getName() + "-- event -- " + JSON.toJSONString(event));
            try {
                synchronized (mutex) {
                    mutex.notifyAll();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public String lock() throws Exception {
        String name = "default";
        String response = null;
        for (;;) {
            synchronized(mutex) {
                //获取所有的子节点并排序
                List<String> children = zk.getChildren(root, false);
                String[] nodes = children.toArray(new String[children.size()]);
                Arrays.sort(nodes);
                System.out.println(JSON.toJSONString(nodes) + "--" + Thread.currentThread().getName());
                if (nodes.length > 0) {
                    //如果当前节点是子节点中最小的节点,那么当前节点获得锁。
                    if ((root + "/" + nodes[0]).equals(response)) {
                        System.out.println(Thread.currentThread().getName() + "-- get lock");
                        return response;
                    } else {
                        //如果当前节点不存在,则创建
                        if (null == response) {
                            response = zk.create(root + "/" + name, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
                            System.out.println(Thread.currentThread().getName() + "-- create znode response " + response);
                        }

                        //此处监听所有小于当前节点的节点中最大的那个,以此减少客户端收到watcher event的次数,也可以减轻服务器端压力,避免羊群效应。(此处是一个优化,不然的话都监听当前持有锁的节点。)
                        String responseNode = response.substring(root.length() + 1 );
                        String lowerNode = null;
                        for (int i = 0; i < nodes.length; i++) {
                            if (nodes[i].equals(responseNode)) {
                                lowerNode = nodes[i - 1];
                            }
                        }

                        Stat stat = zk.exists(root + "/" + lowerNode, true);
                        if (null == stat) {
                            //如果监听的节点不存在,继续!
                            System.out.println(Thread.currentThread().getName() + "-- null " + lowerNode);
                            continue;
                        } else {
                            System.out.println(Thread.currentThread().getName() + "-- listener " + lowerNode);
                            mutex.wait();
                            System.out.println(Thread.currentThread().getName() + "-- continue ");
                        }
                    }
                } else {
                    //如果当前没有任何子节点,那么创建。
                    response = zk.create(root + "/" + name, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
                    System.out.println(Thread.currentThread().getName() + "-- create znode");
                    System.out.println(Thread.currentThread().getName() + "-- create znode response " + response);
                }
            }
        }
    }

    public void unlock(String name) throws Exception {
        synchronized (mutex) {
            zk.delete(name, -1);
            System.out.println(Thread.currentThread().getName() + "-- unlock -- " + name );
        }
    }
}
基于zookeeper实现分布式锁 前言:2016春节之后一直比较忙,因此博客N个没有更新,现在也是忙里偷闲,偷偷的更新一篇! 一、分布式锁介绍         分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性。 二、架构介绍         在介绍使用Zookeeper实现分布式锁之前,首先看当前的系统架构图 阅读详情

相关推荐

springboot基于zookeeper实现分布式锁

参考链接: https://blog.youkuaiyun.com/wuzhiwei549/article/details/80692278 https://blog.52itstyle.vip/archives/3202/ 先说明一下zookeeper实现分布式锁的原理,这里参看csdn一篇非常好的文章,如果不想看原理直接跳过看后面的具体代码实现 单机应用架构中,秒杀案例使用ReentrantLcok或者s...

holmes369的博客 3453

zookeeper分布式锁超时没有自动释放

在使用ZK分布式锁时,我们使用的是zk的临时节点,当系统宕机或者异常终止导致节点删除没有被显示调用时,锁将不释放。 此时只能依靠zk自身的sessionTimeout来删除节点。 如果sessionTimeout后依然没有删除节点,考虑是否是zk集群服务器时间不一致的问题。

qqXHwwqwq的博客 8735

基于ZooKeeper的分布式锁实现(C++版本)

一、简介分布式同步是Zookeeper的功能之一,但Zookeeper的分布式同步(分布式锁)功能并非以直接的接口呈现的。开发者需要额外地基于Zookeeper的节点(node)的分布式同步特性来实现分布式锁的接口。本文将提供基于基于ZooKeeper的分布式锁的C++接口及实现,实现中用到了部分C++11特性。另外,本实现使用的是经过封装的ZooKeeper接口,本文只列出这些ZooKeeper...

warden007的博客 3772

分布式锁(Zookeeper)

在单体应用开发的时候,涉及到并发的问题时候,往往会使用synchronized或者Lock的方式来解决多线程间的数据不一致等各种问题。 但是在集群的项目结构中,Synchronized就再起作用了,为什么呢? synchronized关键字的作用域其实是一个进程,在这个进程下面的所有线程都能够进行加锁。但是多进程就不行了。对于集群项目来说,每个地区都可能有一台服务器。这样不同地区服务器不一样,地址不一样,进程也不一样。因此synchronized无法保证数据的一致性。

weixin_44491927的博客 2445

告别实车测试:手把手教你用Vector VT平台搭建OBC/DCDC的HIL测试台架

本文详细介绍了如何利用Vector VT平台搭建新能源汽车OBC/DCDC的HIL测试台架,涵盖硬件选型、模型部署到自动化测试的全流程。通过HIL仿真测试技术,工程师可以高效验证动力域关键部件,大幅缩短开发周期并降低成本,特别适合新能源汽车三电系统的开发验证。

weixin_42659194的博客 338

STM8库函数开发手册(3) //UART1、内部EEPROM、FLASH操作库、IIC(硬、软)

STM8S 微控制器家族的通用同步异步收发器(UART1,UART2 或者UART3)提供了一种灵活的方法与使用工业标准NRZ 异步串行数据格式的外部设备之间进行全双工数据交换。STM8 的UART 提供范围的波特率选择,并且支持多处理器通讯。UART 也支持LIN(局部互联网)协议版本1.3,2.0,和2.1 以及在主模式下的J2602。 UART1 和UAR...

finedayforu的博客 2520

Zookeeper分布式锁的实现方案

Zookeeper实现分布式锁 在分布式场景中,虽然可以用Redis实现分布式锁的概念,但是Redis在实现的过程中需要考虑到客户端锁释放以及客户端挂掉的种种情况发生。但是Zookeeper由于是基于临时节点实现的锁,所以当客户端挂掉的时候,会自动释放锁。所以我们只需要关注用锁,释放锁的流程就行。{{{width=“100” height=“100”}}} 实现方案 目前有两种,一是使用JDK的API底层实现、二是使用市场上已经成熟的Zookeeper分布式锁框架 CURATOR。 JDK 先直接贴上代码

weixin_42454225的博客 812

面试篇 - LoRA(Low-Rank Adaptation) 原理

输出示例:trainable params: 262,144 || all params: 6,742,016,000 || trainable%: 0.0039。论文实验显示:零初始化 BB 可使初始损失与预训练模型相差不足0.1%,而非零初始化可能差50%+。若初始 ΔW≠0,模型可能立即偏离预训练学到的知识(如GPT-3突然忘记如何造句)。:如同汽车改装,先保持原厂配置(W),再逐步加装新部件(ΔW),避免直接飙车失控。:大模型的权重变化矩阵 ΔWΔW 通常是低秩的(少数主成分主导变化)。

qq_60245590的博客 1151

zookeeper实现分布式锁

介绍了Zookeeper如何实现分布式锁,并使用代码进行了演示

凉茶铺的博客 6971

跨模型的 API 调用与集成:使用 Spring AI 构建可移植的 API 代码,支持多个 AI 模型(如 OpenAI、Anthropic 等)的调用

Spring AI 是 Spring 生态系统中的一部分,旨在提供一种简单、可扩展的方式来集成人工智能模型。Spring AI 使得开发者可以使用现有的 Spring 体系结构方便地访问多种 AI 模型和服务,例如 OpenAI、Anthropic、HuggingFace 等。

秋元的博客 2404

QCPColorMap实现瀑布图

QCPColorMap实现真正的瀑布图

pf1873252141的博客 5268

Zookeeper-分布式锁

一、zookeeper基础知识 1、zookeeper节点 Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode。 2、zookeeper节点类型 Znode分为四种类型: 1)持久节点(PERSISTENT) 默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。 2)持久节点顺序节点(PERSISTENT_SEQUE...

mazhongjia的博客 1288

Linux内核配置选项详解及编译过程

在内核编译完成后,可以通过重启系统并选择新编译的内核来使用它。可以在该菜单下选择需要编译进内核的设备驱动,也可以选择将设备驱动编译为模块。可以在该菜单下选择需要编译进内核的设备驱动,也可以选择将设备驱动编译为模块。可以选择需要的调试选项,并根据需要启用或禁用相应的功能。可以选择需要的文件系统类型,并根据需要启用或禁用相应的选项。可以选择需要的网络协议和功能,并根据需要启用或禁用相应的选项。可以选择需要的调试选项,并根据需要启用或禁用相应的功能。可以选择需要的文件系统类型,并根据需要启用或禁用相应的选项。

TechGlide的博客 746

Zookeeper分布式锁实现

zookeeper最初设计的初衷就是为了保证分布式系统的一致性。本文将讲解如何利用zookeeper的临时顺序结点,实现分布式锁。

2301_76632762的博客 1373

从业务角色到工作台:一步步创建 SAP Fiori Launchpad Space 与 Page

SAP S/4HANA Launchpad 配置优化指南:从业务角色出发构建高效工作台 本文针对S/4HANA项目中用户普遍反映的"入口难找"问题,提出基于Spaces和Pages的系统化解决方案。通过"以工作岗位为中心"的设计理念,将Launchpad信息架构重构为:一个业务角色对应一个Space,每个Space包含1-5个Page,Page内按任务划分2-5个Section,每个Section放置3-7个Tiles。文章详细阐述了从Business Role入手配

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 223

【制作100个unity实战之2】实现一款简单的FPS游戏

你将学到: fps武器脚本 基础瞄准功能 僵尸敌人AI 巡逻范围 攻击间 搜寻半径 追击 枪声吸引周围的僵尸 击中僵直效果

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 3550

图解curator如何实现zookeeper分布式锁

curator提供的四种分布式锁概述(InterProcessMutex、InterProcessSemaphoreMutex、InterProcessReadWriteLock、InterProcessMultiLock),Zookeeper分布式锁实现思路,Zookeeper分布式锁解决的问题,Zookeeper分布式锁优缺点,InterProcessMutex实现zookeeper分布式原理/源码解析,图解curator解锁 / 解锁流程

健身变秃,coding变强 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Zookeeper实战——分布式锁实现以及原理

文章目录Zookeeper 分布式锁实现原理具体流程代码实现客户端创建工厂类创建 Lock 锁接口Lock 实现类(ZkLock)自定义 ZK 分布式锁测试独占锁 & 共享锁Curator 实现分布式锁ZooKeeper 分布式锁的优缺点 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。分布式锁的实现方式有很多种,比如 Redis 、数据库 、zookeeper 等。这篇文章主要介绍用 Zookeeper 实现分布式锁。 Zookeeper 分布式锁实现原理 先说结论:Zookeeper.

KIMTOU的博客 1万+

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

zookeeper - 实现分布式锁

zookeeper - 实现分布式锁

qq_43350524的博客 1403

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Zookeeper 及 基于ZooKeeper实现的分布式锁

ZooKeeper是一个开源的分布式协调服务,它的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。原语:操作系统或计算机网络用语范畴。是由若干条指令组成的,用于完成一定功能的一个过程。具有不可分割性,即原语的执行必须是连续的,在执行过程中不允许被中断。

rc1596919047的博客 1571

zookeeper实现分布式锁-curator

前言 在之前《Redis实现分布式锁》一文中我已经介绍了使用Redis实现分布式锁原理,今天主要是介绍一下如何使用zookeeper实现分布式锁。 一.zookeeper介绍和安装 1.zookeeper介绍 1.1.什么是zookeeper ZooKeeper由雅虎研发,是Google Chubby的开源实现,目前托管给Apache,是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。 分布式应用程序可以基于ZooKeeper实现数

墨家巨子@俏如来 2921

基于Zookeeper实现分布式锁

在Zookeeper中的指定路径下创建创建节点,然后客户端根据当前路径下的节点状态来判断是否加锁成功,如下图一种情况为例,线程1创建节点成功后,线程2再去创建节点就会创建失败。(3)如果加锁次数等于0,则释放锁,删除掉创建的临时节点,下一个监听这个节点的客户端会感知到节点删除事件,从而重新去获取锁。3:判断自己的序号是否最小,如果最小的话,代表加锁成功,如果不是最小的话,就对前一个节点创建监听器。2:使用顺序节点的好处是,可以利用锁释放的事件监听机制,来实现。2:第二步客户端拿到加锁路径下所有创建的节点。

weixin_45125989的博客 2915

基于Zookeeper实现分布式锁实践

基于Zookeeper实现分布式锁实践。Zookeeper是一个分布式的,开源的分布式应用程序协调服务,是Hadoop和hbase的重要组件。zookeeper的数据机构是一种节点树的数据结构,zNode是基本的单位,znode是一种和unix文件系统相似的节点,可以往这个节点存储或向这个节点获取数据

Nicky's blog 2993
上一篇: Go资料汇总
下一篇: MyBatis原理--配置解析
java_4_ever
博客等级 码龄16年 8粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值