当前位置: 首页 > news >正文

分布式锁3: zk实现分布式锁3 使用临时顺序节点+watch监听实现阻塞锁

一  zk实现分布式锁

1.1 使用临时顺序节点 的问题

接上一篇文章,每个请求要想正常的执行完成,最终都是要创建节点,如果能够避免争抢必然可以提高性能。这里借助于zk的临时序列化节点,实现分布式锁

1. 主要修改了构造方法和lock方法:

2.并添加了getPreNode获取前置节点的方法。

存在的问题就是羊群效应。 

1.2  使用临时顺序节点+watch监听实现阻塞锁

假如当前有1000个节点在等待锁,如果获得锁的客户端释放锁时,这1000个客户端都会被唤醒,这种情况称为“羊群效应”。

在这种羊群效应中,zookeeper需要通知1000个客户端,这会阻塞其他的操作,最好的情况应该只唤醒新的最小节点对应的客户端。应该怎么做呢?在设置事件监听时,每个客户端应该对刚好在它之前的子节点设置事件监听,例如子节点列表为/locks/lock-0000000000、/locks/lock-0000000001、/locks/lock-0000000002,序号为1的客户端监听序号为0的子节点删除消息,序号为2的监听序号为1的子节点删除消息。

1.3  使用临时顺序节点+watch监听实现阻塞锁的算法逻辑

1.客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为/locks/lock-0000000000,第二个为/locks/lock-0000000001,以此类推;

2.客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁;

3.执行业务代码;

4.完成业务流程后,删除对应的子节点释放锁。

二  操作步骤

2.1 代码

2.1.1 zk的客户端

初始化则创建临时序列化节点

2.1.2 分布式锁代码

package com.atguigu.distributed.lock.config;import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.*;import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;/*** @ClassName: ZkDistributedTempLock* @Description: TODO* @Author: admin* @Date: 2024/01/06 11:05:09 * @Version: V1.0**/
public class ZkDistributedTempLock implements Lock {private static final String ROOT_PATH = "/d-zk";private String path;private ZooKeeper zooKeeper;public ZkDistributedTempLock(ZooKeeper zooKeeper,String lockName) throws KeeperException, InterruptedException {this.zooKeeper = zooKeeper;// this.path = ROOT_PATH + "/" + lockName+"-";this.path = zooKeeper.create(ROOT_PATH + "/" + lockName + "-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);}public void lock() {try {String preNode = getPreNode(path);// 如果该节点没有前一个节点,说明该节点时最小节点,放行执行业务逻辑if (StringUtils.isEmpty(preNode)) {return;} else {//有前一个节点,阻塞,对前一个节点进行监听CountDownLatch countDownLatch = new CountDownLatch(1);if (this.zooKeeper.exists(ROOT_PATH + "/" + preNode, new Watcher() {@Overridepublic void process(WatchedEvent event) {System.out.println("当前节点=="+path+" 前一个节点:"+ROOT_PATH + "/" + preNode);countDownLatch.countDown();}}) == null) {return;}// 阻塞。。。。countDownLatch.await();return;}} catch (InterruptedException | KeeperException e) {// 重新检查。是否获取到锁try {Thread.sleep(20);} catch (InterruptedException ex) {ex.printStackTrace();}lock();}}@Overridepublic void lockInterruptibly() throws InterruptedException {}@Overridepublic boolean tryLock() {return false;}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return false;}@Overridepublic void unlock(){try {this.zooKeeper.delete(path, 0);} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}}/*** 获取指定节点的前节点* @param path* @return*/private String getPreNode(String path){System.out.println("path:"+path);try {// 获取当前节点的序列化号Long curSerial = Long.valueOf(StringUtils.substringAfterLast(path, "-"));// 获取根路径下的所有序列化子节点List<String> nodes = this.zooKeeper.getChildren(ROOT_PATH, false);// 判空if (CollectionUtils.isEmpty(nodes)){return null;}// 获取前一个节点Long flag = 0L;String preNode = null;for (String node : nodes) {// 获取每个节点的序列化号Long serial = Long.valueOf(StringUtils.substringAfterLast(node, "-"));if (serial < curSerial && serial > flag){flag = serial;preNode = node;}}return preNode;} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}return null;}@Overridepublic Condition newCondition() {return null;}
}

2.1.3 service层

2.1.4 controller层

2.2 nginx代理多服务节点访问

1.服务启动

2.nginx启动

3.jemeter访问

2.3 测试

数据库初始化

测试后

相关文章:

分布式锁3: zk实现分布式锁3 使用临时顺序节点+watch监听实现阻塞锁

一 zk实现分布式锁 1.1 使用临时顺序节点 的问题 接上一篇文章&#xff0c;每个请求要想正常的执行完成&#xff0c;最终都是要创建节点&#xff0c;如果能够避免争抢必然可以提高性能。这里借助于zk的临时序列化节点&#xff0c;实现分布式锁 1. 主要修改了构造方法和lock方…...

google drive api

1.创建oauth2 json 文件 https://developers.google.com/drive/api/quickstart/pythoncchttps://developers.google.com/drive/api/quickstart/python这里要注意quickstart的code会经常更新&#xff0c;有可能之前的版本不能用了 比方说下面这个包 from google.oauth2.crede…...

3_代理模式(动态代理JDK原生和CGLib)

一.代理模式 1.概念 代理模式(Proxy Pattern )是指为其他对象提供一种代理&#xff0c;以控制对这个对象的访问&#xff0c;属于结构型模式。 在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的…...

Linux的权限(1)

目录 操作系统的"外壳"程序 外壳程序是什么&#xff1f; 为什么存在外壳程序&#xff1f; 外壳程序怎么运行操作&#xff1f; 权限 什么是权限&#xff1f; 权限的本质&#xff1f; Linux中的&#xff08;人&#xff09;用户权限&#xff1f; su和su -的区别…...

数据安全保障的具体措施有哪些

随着信息化时代的到来&#xff0c;数据已经成为企业和社会发展的重要资产。然而&#xff0c;数据安全问题也日益突出&#xff0c;如何保障数据的安全性、完整性和可用性成为了亟待解决的问题。以下将详细探讨数据安全保障的各个方面&#xff0c;以期为企业和社会提供更好的数据…...

浅谈标签及应用场景

一、标签的定义 标签是根据业务场景的需求&#xff0c;通过对目标对象&#xff08;包含静态、动态特性&#xff09;&#xff0c;运用抽象、归纳、推理等算法得到的高度精炼的特征标识&#xff0c;用于差异化管理与决策。标签由标签名称和标签值组成&#xff0c;打在目标对象上…...

Linux动态分配IP与正向解析DNS

目录 一、DHCP分配 1. 动态分配 1.1 服务端服务安装 1.2 修改服务端dhcp配置 1.3 修改客户端dhcp&#xff0c;重启查询网卡信息 2. 根据mac固定分配 2.1 修改服务器端dhcp服务配置 2.2 客户端自动获取&#xff0c;查看网卡信息 二、时间同步 1. 手动同步 2. 自动同…...

pyspark 使用udf 进行预测,发现只起了一个计算节点

PySpark UDF 只使用一个计算节点的问题 原因分析 默认的并行度设置 PySpark在执行UDF&#xff08;用户定义函数&#xff09;时&#xff0c;默认可能不会利用所有可用的计算节点。这是因为UDF通常在单个节点上执行&#xff0c;并且如果没有正确设置分区&#xff0c;可能会导致数…...

mysql触发器的简单使用

mysql触发器 触发器是一个特殊的存储过程&#xff0c;在事件delete、insert、update发生时自动执行一条或多条SQL语句&#xff08;执行多条SQL语句需要用begin、end 包裹起来&#xff09; 创建触发器 创建触发器的四大必要条件 唯一的触发器名称触发器关联的表触发器响应的…...

全志T113开发板Qt远程调试

1引言 通常情况下工程师在调试Qt程序时&#xff0c;需要频繁制作镜像烧录到核心板来测试Qt程序是否完善&#xff0c;这样的操作既费时又费力。这时我们可以通过QtCreator设备功能&#xff0c;定义设备后&#xff0c;在x86_64虚拟机上交叉编译qt程序&#xff0c;将程序远程部署到…...

学习使用php、js脚本关闭当前页面窗口的方法

学习使用php、js脚本关闭当前页面窗口的方法 前言方法一&#xff1a;使用JavaScript代码方法二&#xff1a;通过http头文件来实现方法三&#xff1a;使用服务器端脚本来实现 前言 在开发web应用程序时&#xff0c;我们通常需要在不同的网页之间进行导航。通常情况下&#xff0…...

python 人脸检测与人脸识别

安装库文件: pip install dlib face_recognition import dlib import face_recognition import cv2 from PIL import Image, ImageDraw# 判断运行环境 cpu or gpu def check_env():print(dlib.DLIB_USE_CUDA)print(dlib.cuda.get_num_devices())# 判断人脸在图片当中的位置 def…...

RT-Thread: ulog 日志 讲解和使用

说明&#xff1a;记录 RT-Thread: ulog 日志功能和使用流程。 官网资料链接&#xff1a; https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog 1.ulog 简介 日志的定义&#xff1a;日志是将软件运行的状态、过程等信息&#x…...

git ssh key 配置

一、Profile Settings-->SSH Keys 我们点击这里会有详情的文档介绍生成sshkey。 ssh-keygen -t rsa -b 2048 -C "邮箱" --回车... 将生成的id_rsa.pub粘贴到如下保存 git config --global user.name "用户名" git config --global user.email "邮…...

MongoDB聚合:$documents

$documents阶段可以根据输入值返回字面意义的文档。 语法 { $documents: <表达式> }$documents接受可解析为对象数组的任何有效表达式&#xff0c;包括&#xff1a; 系统变量&#xff0c;如 $$NOW 或 $$SEARCH_META $let 表达式 $lookup 表达式作用域中的变量 没有…...

程序员英语 - 英文会议常用句型

相信大部分程序员都会有如下经历&#xff1a; 产品经理&#xff08;BA&#xff09;们在和外系统聊集成方案时或者给用户解决某个问题时发现搞不定了&#xff0c;这个时候就会拉上程序员一起上会参与讨论或者排查问题&#xff0c;但程序员们英文又不好&#xff0c;上了会又听不懂…...

UV贴图和展开初学者指南

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 介绍 这正是本文的主题——UV贴图——登上舞台的时候。大多数 3D 建…...

解密Path环境变量

解密Path环境变量 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一起深入探讨程序开发中不可或缺的一项关键技术——“path环境变量”。无论…...

git撤销提交到本地的commit

有些时候&#xff0c;当我们提交代码到本地后&#xff0c;突然发现因为某些原因需要撤销提交本地的代码。 就比如我&#xff0c;因为代码写错了分支&#xff0c;已经提交到本地了&#xff0c;而我需要取消&#xff0c;并且还要把代码搞得另外的分支上。 提交前&#xff1a; …...

使用Adobe Acrobat Pro DC给pdf文件填加水印

前言 GPT4的官方售价是每月20美元&#xff0c;很多人并不是天天用GPT&#xff0c;只是偶尔用一下。 如果调用官方的GPT4接口&#xff0c;就可以按使用量付费&#xff0c;用多少付多少&#xff0c;而且没有3个小时内只能提问50条的使用限制。 但是对很多人来说调用接口是比较麻烦…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...