使用es实现轻量级分布式锁
文章目录
- @[toc]
- 1.前言
- 2.实现
- 3.总结
文章目录
- @[toc]
- 1.前言
- 2.实现
- 3.总结
1.前言
一般来说,实现分布式锁的方式有哪几种?
一:Redisson实现
二:ZK实现
这两种实现网上的实现是千篇一律,在本文就不做过多的讲解了
其它方式好像没有了,真的是这样么?
答案是否定的,今天我就给大家分享一个新的思路,使用es实现一个分布式锁,分布式锁其本质就是在一个分布式环境下的一个共享变量的(标志位)的获取,哪个线程先获取到了这个标志位就获得了锁,反之,就只能重试轮询等待,类似于java中的CAS,只不过是在分布式环境下,因为在分布式环境下是多微服务和多节点的,所以一个服务会部署多个节点,此时在高并发环境下就需要借助分布式锁来保证分布式环境下高并发线程操作的安全性,所以才会有分布式 锁的这个玩意。
2.实现
废话不多说,直接上代码,关于es怎么整合这里就不做过多的讲解,之前的文章中也有分享,所以这个步骤忽略
LockUtils
package xxxx.utils;import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.builder.SearchSourceBuilder;import java.io.IOException;/*** 基于es写的轻量级分布式锁,可避免引入redis/zk等其它依赖**/
@Slf4j
public class LockUtils {/*** id字段名*/private final static String ID_FIELD = "_id";/*** 重试等待时间*/private final static Integer WAIT_SECONDS = 1;/*** 锁的index的名称*/private final static String LOCK_INDEX = "ee-distribute-lock";private final static Integer ZERO = 0;private final static Integer ONE = 1;private final static String DISTRIBUTED_LOCK_TIP_JSON = "{\"tip\":\"Do not delete unless deadlock occurs\"}";/*** 尝试获取es分布式锁** @param client RestHighLevelClient* @param idValue 相当于key* @param maxRetry 最大重试次数* @return 是否获取成功*/public static synchronized boolean tryLock(RestHighLevelClient client, String idValue, Integer maxRetry) {boolean existsIndex = existsIndex(client, LOCK_INDEX);if (!existsIndex) {createEmptyIndex(client, LOCK_INDEX);}if (maxRetry <= ZERO) {return Boolean.FALSE;}if (getCount(client, idValue) > ZERO) {try {Thread.sleep(WAIT_SECONDS / maxRetry);} catch (InterruptedException e) {e.printStackTrace();}return tryLock(client, idValue, --maxRetry);} else {return createLock(client, idValue);}}/*** 创建锁** @param client RestHighLevelClient* @param idValue 相当于key* @return 是否创建成功*/private static boolean createLock(RestHighLevelClient client, String idValue) {IndexRequest indexRequest = new IndexRequest(LOCK_INDEX);indexRequest.id(idValue);indexRequest.source(DISTRIBUTED_LOCK_TIP_JSON, XContentType.JSON);IndexResponse response;try {response = client.index(indexRequest, RequestOptions.DEFAULT);} catch (IOException e) {e.printStackTrace();return Boolean.FALSE;}return response.status().equals(RestStatus.CREATED);}/*** 释放锁** @param client RestHighLevelClient* @param idValue id字段值实际未entityClass名,一个entity对应一把锁* @param maxRetry 最大重试次数* @return 是否释放成功*/public synchronized static boolean release(RestHighLevelClient client, String idValue, Integer maxRetry) {DeleteRequest deleteRequest = new DeleteRequest(LOCK_INDEX);deleteRequest.id(idValue);if (maxRetry <= ZERO) {return Boolean.FALSE;}DeleteResponse response;try {response = client.delete(deleteRequest, RequestOptions.DEFAULT);} catch (IOException e) {return retryRelease(client, idValue, --maxRetry);}if (RestStatus.OK.equals(response.status())) {return Boolean.TRUE;} else {return retryRelease(client, idValue, maxRetry);}}/*** 重试释放** @param client RestHighLevelClient* @param idValue 相当于key* @param maxRetry 最大重试次数* @return 是否重试成功*/private static boolean retryRelease(RestHighLevelClient client, String idValue, Integer maxRetry) {try {Thread.sleep(WAIT_SECONDS / maxRetry);} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}return release(client, idValue, --maxRetry);}/*** 获取个数** @param client RestHighLevelClient* @param idValue 相当于key* @return 该id对应的锁的个数, 如果>0 说明已有锁,需重试获取,否则认为无锁*/private static Integer getCount(RestHighLevelClient client, String idValue) {SearchRequest searchRequest = new SearchRequest();searchRequest.indices(LOCK_INDEX);SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.termQuery(ID_FIELD, idValue));searchRequest.source(searchSourceBuilder);SearchResponse response;try {response = client.search(searchRequest, RequestOptions.DEFAULT);} catch (IOException e) {e.printStackTrace();return ONE;}return (int) response.getHits().getTotalHits().value;}/*** 创建空索引,不含字段** @param client RestHighLevelClient* @param indexName 索引名* @return 是否创建成功*/public static boolean createEmptyIndex(RestHighLevelClient client, String indexName) {CreateIndexRequest request = new CreateIndexRequest(indexName);CreateIndexResponse createIndexResponse;try {createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);} catch (IOException e) {log.info("===> distribute lock index has created");return Boolean.TRUE;}return createIndexResponse.isAcknowledged();}/*** 是否存在索引** @param client RestHighLevelClient* @param indexName 索引名* @return 是否存在*/public static boolean existsIndex(RestHighLevelClient client, String indexName) {GetIndexRequest request = new GetIndexRequest(indexName);try {return client.indices().exists(request, RequestOptions.DEFAULT);} catch (IOException e) {throw new RuntimeException("existsIndex exception indexName:" + indexName + "ex:" + e.getMessage());}}}
这个实现是看了easyEs2.x的core的核心包里面的一个工具类的源码扣出来改造了下,是直接可以使用的,easyEs1.x的算是比较稳定的,easyEs2.x还是beta版本,所以不建议使用,最近遇到一个小伙伴使用easyEs2.x在项目中使用了,然后,测试环境可以连接上es服务端,但是后面他们去华为云采购了华为的es,华为的es版本好像最高是7.10的,而easyEs里面依赖的es的版本是7.14,后面部署项目就一直连接不上华为云的es,报错连接被拒绝,由于他们项目赶着上线,任务重,所以只能自己在华为云上搭建了一个es集群,后续在处理这个问题,自己搭建的es可以连上,后面他说又有一个问题翻车了,就是索引的自动托管会有问题,所以还是不建议使用这个开源的项目,最好还是使用官方提供的那个restful的高级客户端,轻量级,也没有过度封装,不像spring-data-elasticsearch这个springBoot提供的集成包,这个也是不建议使用的,过度封装,会有意想不到的bug,如果你要使用easyEs2.x的话官方的建议是你需要做好修改源码的准备,出了问题只能自己搞定了,所以还是自己集成官方restful的高级客户端,关键还是要对es的DSL语法要熟悉和es的原理掌握要666的。对于这种开源项目适合于学习使用,源码写的还是挺好的,别有洞天,代码清秀工整美观,看着就赏心悦目,这不就是我们所追求的梦中情码么,哈哈哈
easyEs官网
https://www.easy-es.cn/pages/7ead0d/#%E7%AE%80%E4%BB%8B
可以使用我之前写的es的启动器,下面的文章里面有分享,看一参看
ES启动器实现及应用间fegin调用fastJson数据解析时间类型转换bug修复
https://mp.weixin.qq.com/s/E7ZckUVvC-v2nUV7AXwEaQ
3.总结
本次分享到此结束,希望我的分享对你有所帮助,请一键三连,么么么哒!
相关文章:
使用es实现轻量级分布式锁
文章目录 [toc] 1.前言2.实现3.总结 1.前言 一般来说,实现分布式锁的方式有哪几种? 一:Redisson实现 二:ZK实现 这两种实现网上的实现是千篇一律,在本文就不做过多的讲解了 其它方式好像没有了,真的是这…...
富文本编辑器特殊字符的解码编码
var HtmlUtil {/*1.用浏览器内部转换器实现html转码*/htmlEncode:function (html){//1.首先动态创建一个容器标签元素,如DIVvar temp document.createElement ("div");//2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐&…...
几种软件开发方法对比
几种软件开发方法对比 1 综述 软件开发方法是一种使用早已定义好的技术集及符号表示习惯来组织软件生产的过程。 本文对净室方法、结构化方法、面向对象方法、原型法、逆向工程等方法进行梳理,并对各种开发方法特点、优点进行对比。 2 净室方法 2.1 特点 净…...
在Maven中发布项目到Nexus私有服务器
一、测试环境 Sonatype Nexus 3.61.0-02 Maven 3.9.2 二、环境配置 2.1找到maven的配置文件 2.2添加私有仓库账户密码 <servers><server><id>nexus</id><username>admin</username><password>admin</password></server&…...
TypeScript - 类 -类的继承
浅谈类的继承 类的继承 就是对一个类进行扩展,可以扩展属性、方法。 类的继承 可以很好的解决代码冗余的问题。比如 : 【学生】类 拥有 基本的 姓名、年龄 两个属性, 【体育生】类也属于【学生】类,有 姓名、年龄、训练项目 三个…...
QT: QLineEdit 密码模式、QLineEdit输入模式
setEchoMode(QLineEdit::Normal) 是一个函数,用于设置 QLineEdit 对象的输入模式。具体用法如下: lineEdit->setEchoMode(QLineEdit::Normal);该函数的作用是将 QLineEdit 对象的输入模式设置为“正常模式”,在此模式下,用户的…...
ES6中Map集合
Map集合是一个新的数据结构,它可以存储键值对,并且可以使用任何类型的值作为键,包括对象、数组和函数。Map也是一种可迭代的结构,可以使用for...of循环遍历。 在ES6中,我们可以使用Map构造函数来创建一个Map集合&…...
【Leetcode Sheet】Weekly Practice 13
Leetcode Test 1155 掷骰子等于目标和的方法数(10.24) 这里有 n 个一样的骰子,每个骰子上都有 k 个面,分别标号为 1 到 k 。 给定三个整数 n , k 和 target ,返回可能的方式(从总共 kn 种方式中)滚动骰子的数量,使正面朝上的数…...
技术贴 | 一文掌握 Google Test 框架
一、简介 1. 引言 在开发过程中,如何保证代码的质量以及程序的正确性成为了我们亟需解决的问题,其中测试用例成为了不必可少的一部分。测试用例不仅可以帮助我们验证代码的正确性,还能帮助我们捕获潜在的错误,提高代码的可靠性和…...
基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类 计算机竞赛
文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层:2.4 池化层:2.5 全连接softmax层:2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…...
非线性时滞系统的无模型预测控制
摘 要 非线性时滞系统的预测控制应用广泛,比如电子设备、石油化工、造纸等行业,都会运用到非线性时滞系统的预测控制系统或工具。更高效率和更高精度的非线性时滞系统的预测控制一直是研究的热点。在我们日常生活中,非线性时滞系统的预测控制…...
局域网内两台电脑共享文件夹(通过网线直连共享数据)
文章目录 2.设置共享文件夹3.访问共享文件夹 1.将两台电脑置于同一局域网下 用网线将两台电脑连接关闭两台电脑防火墙将两台电脑IP地址设置在同一局域网下 测试是否在同一局域网下,使用ping命令 ping 192.168.0.122.设置共享文件夹 选择想要共享的文件夹ÿ…...
什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(3)
参考视频:https://www.youtube.com/watch?vE5Z7FQp7AQQ&listPLuhqtP7jdD8CD6rOWy20INGM44kULvrHu 视频7:CNN 的全局架构 卷积层除了做卷积操作外,还要加上 bias ,再经过非线性的函数,这么做的原因是 “scaled p…...
一致性hash负载均衡
Hash算法的问题 今天看下一致性hash,常见的负载均衡可能使用过hash,比如nginx中,如果使用session最简单就是通过hash,比如根据用户的请求ip进行hash,让不同用户的请求打到同一台服务器,这样状态处理起来最…...
MAC下安装Python
MAC基本信息: 执行命令: brew install cmake protobuf rust python3.10 git wget 遇到以下问题: > Downloading https://mirrors.aliyun.com/homebrew/homebrew-bottles/rust-1.59.0 Already downloaded: /Users/xxxx/Library/Caches/Ho…...
Android NDK开发详解之JNI中的库文件
Android NDK开发详解之JNI中的库文件 简介工作原理流程原生 activity 和应用 简介 本部分简要介绍了 NDK 的工作原理。Android NDK 是一组使您能将 C 或 C(“原生代码”)嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下…...
KNN模型
使用K-Nearest Neighbors (KNN)算法进行分类。首先加载一个数据集,然后进行预处理,选择最佳的K值,并训练一个KNN模型。 # encodingutf-8 import numpy as np datas np.loadtxt(datingTestSet2.txt) # 加载数据集,返回一个numpy数…...
Python 学习1 基础
文章目录 基础字符串字面量常用的值类型注释变量print语句数据类型数据类型转换标识符运算符 字符串拓展小结 2023.10.28 周六 最近打算学一下Python,毕竟确实简单方便,而且那个编程语言排名还是在第一。不过不打算靠它吃饭,深不深入暂且不说…...
网络协议--TCP的超时与重传
21.1 引言 TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认,它就重传该数据。对任何实现而言,关键之处就在于超时和重…...
Thread
Thread 线程启动线程第一种创建线程线程的第二种创建方式使用匿名内部类完成线程的两种创建 Thread API线程的优先级线程提供的静态方法守护线程用户线程和守护线程的区别体现在进程结束时 多线并发安全问题同步块 线程 启动线程 启动线程:调用线程的start方法,而不是直接调用…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
