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级别的锁,比如synchronized、Lock等来实现锁,如果是多机部署就需要一个共享数据存储区域来实现分布式锁 一、分布式锁实现方式 1、基于数据库实现分布式锁 可以用数据库唯一索引来实现 2、基于redis实现分布式锁 redis实现的分…...
Android webView加载高德地图定位不显示问题
如果只显示地图 val webView: WebView findViewById(R.id.webView)webView.settings.javaScriptEnabled truewebView.loadUrl("https://test.cn")//h5地址 如果需要定位,则需要加以下代码,否则不弹窗 webView.webChromeClient object : We…...
94. 二叉树的中序遍历(递归+迭代)
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 解题思路: 方法一:递归 中序遍历的操作定义为,若二叉树为空,则空操作,否则: 中序遍历左子树访问根节点中…...
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语言中的按位或运算符 | 时,需要理解其用途、应用场景、示例源代码以及相应的注意事项。以下是一篇关于Java语言按位或运算符的详细文章,包括示例源代码和注释。 Java语言中的按位或运算符 | 按位或运算符 | 是Java语言中用于对二进制位进行…...
C多线程编程- 近似求解π
本程序使用蒙特卡洛方法估算圆周率(π)。它首先创建了指定数量的线程,每个线程生成一个随机点并检查该点是否在单位圆内。基于这些线程的结果,程序计算在单位圆内的点的比例,并乘以4来估算π的值。为了对比,…...
YOLOV7量化第二步: 模型标定
2.模型标定 当然可以,模型量化中的标定(calibration)是一个关键过程,它主要确保在降低计算精度以减少模型大小和提高推理速度的同时,不会显著损害模型的准确性。现在,我将根据您提供的步骤解释这一过程。 …...
前端-uniapp-开发指南
美团外卖微信小程序开发 uniapp-美团外卖微信小程序开发P1 成果展示P2外卖小程序后端,学习给小程序写http接口P3 主界面配置P4 首页组件拆分P13 外卖列表布局筛选组件商家 布局测试数据创建样式 请求商家外卖数据封装请求并发请求 uni-app框架调用https接口 开发小程…...
Java集合类ArrayList的应用-杨辉三角的前n行
目录 一、题目 杨辉三角 二、题解 三、代码 四、总结 一、题目 题目链接:https://leetcode.cn/problems/pascals-triangle/description/ 杨辉三角 题目描述:给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨…...
C语言-函数
函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() 。 主函数可以调用其他函数,其他函数也可以相互调用,用户也可以那个自定义函数。 函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实…...
蓝桥杯 枚举算法 (c++)
枚举就是根据提出的问题,——列出该问题的所有可能的解,并在逐一列出的过程中,检验每个可能解是否是问题的真正解, 如果是就采纳这个解,如果不是就继续判断下一个。 枚举法一般比较直观,容易理解࿰…...
Wordpress自定义小工具logo调用设置(可视化)
在主题开发中,需要调用网站的logo,最简单的办法就是用wp自带的函数,那就是the_custom_logo(),使用它还可以通过后台-自定义-logo,边修改边预览,还是很香的。 自定义徽标支持应首先使用add_theme_support()添…...
面试常考数据结构:红黑树、B树、B+树各自适用的场景
1. 磁盘基础知识 分页: 现代操作系统都使用虚拟内存来印射到物理内存,内存大小有限且价格昂贵,所以数据的持久化是在磁盘上。虚拟内存、物理内存、磁盘都使用页作为内存读取的最小单位。一般一页为4KB(8个扇区,每个扇…...
Paddle GPU版本需要安装CUDA、CUDNN
完整的教程 深度学习环境配置:linuxwindows系统下的显卡驱动、Anaconda、Pytorch&Paddle、cuda&cudnn的安装与说明 - 知乎这篇文档的内容是尽量将深度学习环境配置(使用GPU)所需要的内容做一些说明,由于笔者只在windows和linux下操作过…...
MYSQL length函数
mysql length函数计算结果的单位是啥,和varchar字段类型的单位是相同的吗? 做了一下实验,结果如下: 1.mysql length 函数计算的是有多少个字符,比如字段值是 permission 则length函数计算结果为10。 2.如果字段类型是…...
uniapp 在android手机上运行tab栏页面跳转问题
【问题描述】: 使用uniapp写的项目,在tab页面,无论使用哪种方式的跳转,只要是在url后面拼接参数,在打包成apk文件后,在手机上面安装使用,都是获取不到susIndex参数的,而在浏览器上面…...
css3 hover效果
CSS3中的:hover伪类用于创建鼠标悬停时的样式效果。当用户将鼠标悬停在页面元素上时,你可以为这些元素定义不同的样式规则,以实现交互效果 /* 一般样式规则 */ element {/* 正常状态下的样式 */ }/* 悬停样式规则 */ element:hover {/* 鼠标悬停时的样式…...
C语言char与short取反以及符号判断问题
这个问题主要是在从对一个变量进行符号判断引出,有一种判断方法是#define ISUNSIGNED(Value) (Value >0 && ~Value >0) 主要是通过将符号位取反然后将变量与0进行比较。传入int与unsigned int结果正确,但是当传入unsigned char 与unsign…...
Gpt-4多模态功能强势上线,景联文科技多模态数据采集标注服务等您来体验!
就在上个月,OpenAI 宣布对ChatGPT 进行重大更新,该模型不仅能够通过文字输入进行识别和分析,还能够通过语音、图像甚至视频等多种模态的输入来获取、识别、分析和输出信息。这一重要技术突破,将促进多模态自然语言处理的发展&…...
【idea】 java: 找不到符号
idea 启动时提示 java: 找不到符号 java: 找不到符号 符号: 方法 getCompanyDisputeCount() 位置: 类型为com.yang.entity.AreaAnalyse的变量 areaAnalyse 在setting ——> Compiler ——>Shared build process VM options: 添加: -Djps.track.ap.dep…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
