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

使用es实现轻量级分布式锁

文章目录

    • @[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.前言 一般来说&#xff0c;实现分布式锁的方式有哪几种&#xff1f; 一&#xff1a;Redisson实现 二&#xff1a;ZK实现 这两种实现网上的实现是千篇一律&#xff0c;在本文就不做过多的讲解了 其它方式好像没有了&#xff0c;真的是这…...

富文本编辑器特殊字符的解码编码

var HtmlUtil {/*1.用浏览器内部转换器实现html转码*/htmlEncode:function (html){//1.首先动态创建一个容器标签元素&#xff0c;如DIVvar temp document.createElement ("div");//2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐&…...

几种软件开发方法对比

几种软件开发方法对比 1 综述 软件开发方法是一种使用早已定义好的技术集及符号表示习惯来组织软件生产的过程。 本文对净室方法、结构化方法、面向对象方法、原型法、逆向工程等方法进行梳理&#xff0c;并对各种开发方法特点、优点进行对比。 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 - 类 -类的继承

浅谈类的继承 类的继承 就是对一个类进行扩展&#xff0c;可以扩展属性、方法。 类的继承 可以很好的解决代码冗余的问题。比如 &#xff1a; 【学生】类 拥有 基本的 姓名、年龄 两个属性&#xff0c; 【体育生】类也属于【学生】类&#xff0c;有 姓名、年龄、训练项目 三个…...

QT: QLineEdit 密码模式、QLineEdit输入模式

setEchoMode(QLineEdit::Normal) 是一个函数&#xff0c;用于设置 QLineEdit 对象的输入模式。具体用法如下&#xff1a; lineEdit->setEchoMode(QLineEdit::Normal);该函数的作用是将 QLineEdit 对象的输入模式设置为“正常模式”&#xff0c;在此模式下&#xff0c;用户的…...

ES6中Map集合

Map集合是一个新的数据结构&#xff0c;它可以存储键值对&#xff0c;并且可以使用任何类型的值作为键&#xff0c;包括对象、数组和函数。Map也是一种可迭代的结构&#xff0c;可以使用for...of循环遍历。 在ES6中&#xff0c;我们可以使用Map构造函数来创建一个Map集合&…...

【Leetcode Sheet】Weekly Practice 13

Leetcode Test 1155 掷骰子等于目标和的方法数(10.24) 这里有 n 个一样的骰子&#xff0c;每个骰子上都有 k 个面&#xff0c;分别标号为 1 到 k 。 给定三个整数 n , k 和 target &#xff0c;返回可能的方式(从总共 kn 种方式中)滚动骰子的数量&#xff0c;使正面朝上的数…...

技术贴 | 一文掌握 Google Test 框架

一、简介 1. 引言 在开发过程中&#xff0c;如何保证代码的质量以及程序的正确性成为了我们亟需解决的问题&#xff0c;其中测试用例成为了不必可少的一部分。测试用例不仅可以帮助我们验证代码的正确性&#xff0c;还能帮助我们捕获潜在的错误&#xff0c;提高代码的可靠性和…...

基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类 计算机竞赛

文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层&#xff1a;2.4 池化层&#xff1a;2.5 全连接softmax层&#xff1a;2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…...

非线性时滞系统的无模型预测控制

摘 要 非线性时滞系统的预测控制应用广泛&#xff0c;比如电子设备、石油化工、造纸等行业&#xff0c;都会运用到非线性时滞系统的预测控制系统或工具。更高效率和更高精度的非线性时滞系统的预测控制一直是研究的热点。在我们日常生活中&#xff0c;非线性时滞系统的预测控制…...

局域网内两台电脑共享文件夹(通过网线直连共享数据)

文章目录 2.设置共享文件夹3.访问共享文件夹 1.将两台电脑置于同一局域网下 用网线将两台电脑连接关闭两台电脑防火墙将两台电脑IP地址设置在同一局域网下 测试是否在同一局域网下&#xff0c;使用ping命令 ping 192.168.0.122.设置共享文件夹 选择想要共享的文件夹&#xff…...

什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(3)

参考视频&#xff1a;https://www.youtube.com/watch?vE5Z7FQp7AQQ&listPLuhqtP7jdD8CD6rOWy20INGM44kULvrHu 视频7&#xff1a;CNN 的全局架构 卷积层除了做卷积操作外&#xff0c;还要加上 bias &#xff0c;再经过非线性的函数&#xff0c;这么做的原因是 “scaled p…...

一致性hash负载均衡

Hash算法的问题 今天看下一致性hash&#xff0c;常见的负载均衡可能使用过hash&#xff0c;比如nginx中&#xff0c;如果使用session最简单就是通过hash&#xff0c;比如根据用户的请求ip进行hash&#xff0c;让不同用户的请求打到同一台服务器&#xff0c;这样状态处理起来最…...

MAC下安装Python

MAC基本信息&#xff1a; 执行命令&#xff1a; brew install cmake protobuf rust python3.10 git wget 遇到以下问题&#xff1a; > 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&#xff08;“原生代码”&#xff09;嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下…...

KNN模型

使用K-Nearest Neighbors (KNN)算法进行分类。首先加载一个数据集&#xff0c;然后进行预处理&#xff0c;选择最佳的K值&#xff0c;并训练一个KNN模型。 # encodingutf-8 import numpy as np datas np.loadtxt(datingTestSet2.txt) # 加载数据集&#xff0c;返回一个numpy数…...

Python 学习1 基础

文章目录 基础字符串字面量常用的值类型注释变量print语句数据类型数据类型转换标识符运算符 字符串拓展小结 2023.10.28 周六 最近打算学一下Python&#xff0c;毕竟确实简单方便&#xff0c;而且那个编程语言排名还是在第一。不过不打算靠它吃饭&#xff0c;深不深入暂且不说…...

网络协议--TCP的超时与重传

21.1 引言 TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认&#xff0c;它就重传该数据。对任何实现而言&#xff0c;关键之处就在于超时和重…...

Thread

Thread 线程启动线程第一种创建线程线程的第二种创建方式使用匿名内部类完成线程的两种创建 Thread API线程的优先级线程提供的静态方法守护线程用户线程和守护线程的区别体现在进程结束时 多线并发安全问题同步块 线程 启动线程 启动线程:调用线程的start方法,而不是直接调用…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...