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

zookeeper应用场景(二)

单机环境下可以利用jvm级别的锁,比如synchronized、Lock等来实现锁,如果是多机部署就需要一个共享数据存储区域来实现分布式锁

一、分布式锁实现方式

1、基于数据库实现分布式锁

可以用数据库唯一索引来实现

2、基于redis实现分布式锁

redis实现的分布式锁始终会有一些问题,即便使用多数写入,主节点挂了,数据丢失还是会存在加锁问题,就是主节点宕机,客户端无法感知

3、基于zookeeper实现分布式锁

1)实现方式一

使用临时节点创建成功获取锁,否则监听临时节点,有个问题,比如1000个线程只有一个会加锁成功,当删除临时节点时999个线程都会去竞争

2)实现方式二

公平锁的实现

4、Curator可重入分布式锁工作流程

从InterProcessMutex类找到acquire()加锁方法

public void acquire() throws Exception {if (!this.internalLock(-1L, (TimeUnit)null)) {throw new IOException("Lost connection while trying to acquire lock: " + this.basePath);}}
1)加锁 
private boolean internalLock(long time, TimeUnit unit) throws Exception {// 获取当前线程Thread currentThread = Thread.currentThread();// threadData类型是ConcurrentMap,从threadData中去拿LockData加锁对象InterProcessMutex.LockData lockData = (InterProcessMutex.LockData)this.threadData.get(currentThread);// 如果拿到了 证明之前加锁了,lockCount重入次数+1if (lockData != null) {lockData.lockCount.incrementAndGet();return true;} else {// 没有拿到开始从zookeeper上创建lock节点String lockPath = this.internals.attemptLock(time, unit, this.getLockNodeBytes());// 创建成功 加锁成功把对象放到threadData中if (lockPath != null) {InterProcessMutex.LockData newLockData = new InterProcessMutex.LockData(currentThread, lockPath);this.threadData.put(currentThread, newLockData);return true;} else {// 加锁失败return false;}}}private static class LockData {// 持有锁的线程final Thread owningThread;// 在zookeeper的锁路径final String lockPath;// 线程加锁次数final AtomicInteger lockCount;private LockData(Thread owningThread, String lockPath) {this.lockCount = new AtomicInteger(1);this.owningThread = owningThread;this.lockPath = lockPath;}}
 2)创建节点返回路径
String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception {long startMillis = System.currentTimeMillis();Long millisToWait = unit != null ? unit.toMillis(time) : null;byte[] localLockNodeBytes = this.revocable.get() != null ? new byte[0] : lockNodeBytes;// 重试次数int retryCount = 0;String ourPath = null;boolean hasTheLock = false;boolean isDone = false;while(!isDone) {isDone = true;try {// 创建临时有序节点ourPath = this.driver.createsTheLock(this.client, this.path, localLockNodeBytes);// 创建的节点是否为最小节点hasTheLock = this.internalLockLoop(startMillis, millisToWait, ourPath);} catch (NoNodeException var14) {// 加锁失败 重试设置重试策略if (!this.client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper())) {throw var14;}isDone = false;}}return hasTheLock ? ourPath : null;}
public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception {String ourPath;// 是否要给节点设置属性 创建的都是临时有序节点if (lockNodeBytes != null) {ourPath = (String)((ACLBackgroundPathAndBytesable)client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)).forPath(path, lockNodeBytes);} else {ourPath = (String)((ACLBackgroundPathAndBytesable)client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)).forPath(path);}return ourPath;}
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception {boolean haveTheLock = false;boolean doDelete = false;try {if (this.revocable.get() != null) {((BackgroundPathable)this.client.getData().usingWatcher(this.revocableWatcher)).forPath(ourPath);}while(this.client.getState() == CuratorFrameworkState.STARTED && !haveTheLock) {// 将子节点进行排序List<String> children = this.getSortedChildren();// 截取创建的节点的序号String sequenceNodeName = ourPath.substring(this.basePath.length() + 1);// 判断是否为最小序号PredicateResults predicateResults = this.driver.getsTheLock(this.client, children, sequenceNodeName, this.maxLeases);if (predicateResults.getsTheLock()) {// 加锁成功haveTheLock = true;} else {// 拿到上一个节点的路径String previousSequencePath = this.basePath + "/" + predicateResults.getPathToWatch();synchronized(this) {try {// 监听上一个节点((BackgroundPathable)this.client.getData().usingWatcher(this.watcher)).forPath(previousSequencePath);if (millisToWait == null) {// 等待this.wait();} else {millisToWait = millisToWait - (System.currentTimeMillis() - startMillis);startMillis = System.currentTimeMillis();if (millisToWait > 0L) {// 超时等待this.wait(millisToWait);} else {doDelete = true;break;}}} catch (NoNodeException var19) {}}}}} catch (Exception var21) {ThreadUtils.checkInterrupted(var21);doDelete = true;throw var21;} finally {if (doDelete) {this.deleteOurPath(ourPath);}}return haveTheLock;}
 3)解锁
public void release() throws Exception {Thread currentThread = Thread.currentThread();InterProcessMutex.LockData lockData = (InterProcessMutex.LockData)this.threadData.get(currentThread);if (lockData == null) {// 分布式场景下什么情况都可能有 所以判断一下throw new IllegalMonitorStateException("You do not own the lock: " + this.basePath);} else {// 重入次数减1int newLockCount = lockData.lockCount.decrementAndGet();if (newLockCount <= 0) {if (newLockCount < 0) {throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + this.basePath);} else {try {// 这里之前应该还有个大于0的判断 在curator5.1.0&zookeeper 3.9.0版本去掉了this.internals.releaseLock(lockData.lockPath);} finally {this.threadData.remove(currentThread);}}}}}

 

5、总结

优点:Zookeeper分布式锁(如InterProcessMutex),具备高可用、可重入、阻塞锁特性,可解决失效死锁问题

缺点:因为需要频繁的创建和删除节点,性能上不如redis

在高性能、高并发场景下,不建议用Zookeeper的分布式锁。而由于Zookeeper的高可靠性,因此在并发量不是太高的应用场景下,还是推荐使用Zookeeper的分布式锁

二、服务注册与发现

1、设计思路

2、实现注册中心的优缺点

优点:

  • 高可用性:ZooKeeper是一个高可用的分布式系统,可以通过配置多个服务器实例来提供容错能力。如果其中一个实例出现故障,其他实例仍然可以继续提供服务。
  • 强一致性:ZooKeeper保证了数据的强一致性。当一个更新操作完成时,所有的服务器都将具有相同的数据视图。这使得ZooKeeper非常适合作为服务注册中心,因为可以确保所有客户端看到的服务状态是一致的。
  • 实时性:ZooKeeper的监视器(Watcher)机制允许客户端监听节点的变化。当服务提供者的状态发生变化时(例如,上线或下线),客户端会实时收到通知。这使得服务消费者能够快速响应服务的变化,从而实现动态服务发现。

缺点:

  • 性能限制:ZooKeeper的性能可能不如一些专为服务注册中心设计的解决方案,如nacos或Consul。尤其是在大量的读写操作或大规模集群的情况下,ZooKeeper可能会遇到性能瓶颈。

3、整合Spring Cloud Zookeeper实现微服务注册中心 

Spring Cloud Zookeeper

第一步:在父pom文件中指定Spring Cloud版本

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>
<properties><java.version>1.8</java.version><spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

注意: springboot和springcloud的版本兼容问题

第二步:微服务pom文件中引入Spring Cloud Zookeeper注册中心依赖

<!-- zookeeper服务注册与发现 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zookeeper-discovery</artifactId><exclusions><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency><!-- zookeeper client -->
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.8.0</version>
</dependency>

注意: zookeeper客户端依赖和zookeeper sever的版本兼容问题

Spring Cloud整合Zookeeper注册中心核心源码入口: ZookeeperDiscoveryClientConfiguration

第三步: 微服务配置文件application.yml中配置zookeeper注册中心地址

spring:cloud:zookeeper:    connect-string: localhost:2181discovery:instance-host: 127.0.0.1

注册到zookeeper的服务实例元数据信息如下:

注意:如果address有问题,会出现找不到服务的情况,可以通过instance-host配置指定

第四步:整合feign进行服务调用

@RequestMapping(value = "/findOrderByUserId/{id}")
public R  findOrderByUserId(@PathVariable("id") Integer id) {log.info("根据userId:"+id+"查询订单信息");//feign调用   R result = orderFeignService.findOrderByUserId(id);return result;
}

相关文章:

zookeeper应用场景(二)

单机环境下可以利用jvm级别的锁&#xff0c;比如synchronized、Lock等来实现锁&#xff0c;如果是多机部署就需要一个共享数据存储区域来实现分布式锁 一、分布式锁实现方式 1、基于数据库实现分布式锁 可以用数据库唯一索引来实现 2、基于redis实现分布式锁 redis实现的分…...

Android webView加载高德地图定位不显示问题

如果只显示地图 val webView: WebView findViewById(R.id.webView)webView.settings.javaScriptEnabled truewebView.loadUrl("https://test.cn")//h5地址 如果需要定位&#xff0c;则需要加以下代码&#xff0c;否则不弹窗 webView.webChromeClient object : We…...

94. 二叉树的中序遍历(递归+迭代)

题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a; 方法一&#xff1a;递归 中序遍历的操作定义为&#xff0c;若二叉树为空&#xff0c;则空操作&#xff0c;否则&#xff1a; 中序遍历左子树访问根节点中…...

UGUI交互组件Slider

一.Slider对象的结构 对象介绍Slider附加Slider组件Background背景Fill Area填充范围Fill填充对象Handle Slider Area滑块移动范围Handle滑块 二.Slider组件属性 属性说明Fill Rect关联填充对象Handle Rect关联滑块对象Direction设置方向Min Value最大取值Max Value最小取值Wh…...

JAVA经典百题之按位或运算符 `|的使用

当学习Java语言中的按位或运算符 | 时&#xff0c;需要理解其用途、应用场景、示例源代码以及相应的注意事项。以下是一篇关于Java语言按位或运算符的详细文章&#xff0c;包括示例源代码和注释。 Java语言中的按位或运算符 | 按位或运算符 | 是Java语言中用于对二进制位进行…...

C多线程编程- 近似求解π

本程序使用蒙特卡洛方法估算圆周率&#xff08;π&#xff09;。它首先创建了指定数量的线程&#xff0c;每个线程生成一个随机点并检查该点是否在单位圆内。基于这些线程的结果&#xff0c;程序计算在单位圆内的点的比例&#xff0c;并乘以4来估算π的值。为了对比&#xff0c…...

YOLOV7量化第二步: 模型标定

2.模型标定 当然可以&#xff0c;模型量化中的标定&#xff08;calibration&#xff09;是一个关键过程&#xff0c;它主要确保在降低计算精度以减少模型大小和提高推理速度的同时&#xff0c;不会显著损害模型的准确性。现在&#xff0c;我将根据您提供的步骤解释这一过程。 …...

前端-uniapp-开发指南

美团外卖微信小程序开发 uniapp-美团外卖微信小程序开发P1 成果展示P2外卖小程序后端&#xff0c;学习给小程序写http接口P3 主界面配置P4 首页组件拆分P13 外卖列表布局筛选组件商家 布局测试数据创建样式 请求商家外卖数据封装请求并发请求 uni-app框架调用https接口 开发小程…...

Java集合类ArrayList的应用-杨辉三角的前n行

目录 一、题目 杨辉三角 二、题解 三、代码 四、总结 一、题目 题目链接&#xff1a;https://leetcode.cn/problems/pascals-triangle/description/ 杨辉三角 题目描述&#xff1a;给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨…...

C语言-函数

函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数&#xff0c;即主函数 main() 。 主函数可以调用其他函数&#xff0c;其他函数也可以相互调用&#xff0c;用户也可以那个自定义函数。 函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实…...

蓝桥杯 枚举算法 (c++)

枚举就是根据提出的问题&#xff0c;——列出该问题的所有可能的解&#xff0c;并在逐一列出的过程中&#xff0c;检验每个可能解是否是问题的真正解&#xff0c; 如果是就采纳这个解&#xff0c;如果不是就继续判断下一个。 枚举法一般比较直观&#xff0c;容易理解&#xff0…...

Wordpress自定义小工具logo调用设置(可视化)

在主题开发中&#xff0c;需要调用网站的logo&#xff0c;最简单的办法就是用wp自带的函数&#xff0c;那就是the_custom_logo()&#xff0c;使用它还可以通过后台-自定义-logo&#xff0c;边修改边预览&#xff0c;还是很香的。 自定义徽标支持应首先使用add_theme_support()添…...

面试常考数据结构:红黑树、B树、B+树各自适用的场景

1. 磁盘基础知识 分页&#xff1a; 现代操作系统都使用虚拟内存来印射到物理内存&#xff0c;内存大小有限且价格昂贵&#xff0c;所以数据的持久化是在磁盘上。虚拟内存、物理内存、磁盘都使用页作为内存读取的最小单位。一般一页为4KB&#xff08;8个扇区&#xff0c;每个扇…...

Paddle GPU版本需要安装CUDA、CUDNN

完整的教程 深度学习环境配置&#xff1a;linuxwindows系统下的显卡驱动、Anaconda、Pytorch&Paddle、cuda&cudnn的安装与说明 - 知乎这篇文档的内容是尽量将深度学习环境配置(使用GPU)所需要的内容做一些说明&#xff0c;由于笔者只在windows和linux下操作过&#xf…...

MYSQL length函数

mysql length函数计算结果的单位是啥&#xff0c;和varchar字段类型的单位是相同的吗&#xff1f; 做了一下实验&#xff0c;结果如下&#xff1a; 1.mysql length 函数计算的是有多少个字符&#xff0c;比如字段值是 permission 则length函数计算结果为10。 2.如果字段类型是…...

uniapp 在android手机上运行tab栏页面跳转问题

【问题描述】&#xff1a; 使用uniapp写的项目&#xff0c;在tab页面&#xff0c;无论使用哪种方式的跳转&#xff0c;只要是在url后面拼接参数&#xff0c;在打包成apk文件后&#xff0c;在手机上面安装使用&#xff0c;都是获取不到susIndex参数的&#xff0c;而在浏览器上面…...

css3 hover效果

CSS3中的:hover伪类用于创建鼠标悬停时的样式效果。当用户将鼠标悬停在页面元素上时&#xff0c;你可以为这些元素定义不同的样式规则&#xff0c;以实现交互效果 /* 一般样式规则 */ element {/* 正常状态下的样式 */ }/* 悬停样式规则 */ element:hover {/* 鼠标悬停时的样式…...

C语言char与short取反以及符号判断问题

这个问题主要是在从对一个变量进行符号判断引出&#xff0c;有一种判断方法是#define ISUNSIGNED(Value) (Value >0 && ~Value >0) 主要是通过将符号位取反然后将变量与0进行比较。传入int与unsigned int结果正确&#xff0c;但是当传入unsigned char 与unsign…...

Gpt-4多模态功能强势上线,景联文科技多模态数据采集标注服务等您来体验!

就在上个月&#xff0c;OpenAI 宣布对ChatGPT 进行重大更新&#xff0c;该模型不仅能够通过文字输入进行识别和分析&#xff0c;还能够通过语音、图像甚至视频等多种模态的输入来获取、识别、分析和输出信息。这一重要技术突破&#xff0c;将促进多模态自然语言处理的发展&…...

【idea】 java: 找不到符号

idea 启动时提示 java: 找不到符号 java: 找不到符号 符号: 方法 getCompanyDisputeCount() 位置: 类型为com.yang.entity.AreaAnalyse的变量 areaAnalyse 在setting ——> Compiler ——>Shared build process VM options: 添加&#xff1a; -Djps.track.ap.dep…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...