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

这篇具有很好参考价值的文章主要介绍了使用es实现轻量级分布式锁。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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.总结

  本次分享到此结束,希望我的分享对你有所帮助,请一键三连,么么么哒!文章来源地址https://www.toymoban.com/news/detail-734994.html

到了这里,关于使用es实现轻量级分布式锁的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【HarmonyOS】API6使用storage实现轻量级数据存储

     写在前面 本篇内容基于API6 JS语言进行开发,通过结合轻量级数据存储开发指导的文档,帮助大家完成一个实际的代码案例,通过这个小案例,可以实现简单数据的存储。 参考文档:文档中心 1、页面布局 首先我们编写一个简单的页面布局,页面中只有一个文本和两个按钮

    2024年02月14日
    浏览(40)
  • Lucene轻量级搜索引擎,真的太强了!!!Solr 和 ES 都是基于它

    Lucene 是一个本地全文搜索引擎,Solr 和 ElasticSearch 都是基于 Lucene 的封装 Lucene 适合那种轻量级的全文搜索,我就是服务器资源不够,如果上 ES 的话会很占用服务器资源,所有就选择了 Lucene 搜索引擎 全文搜索的原理是使用了倒排索引,那么什么是倒排索引呢? 先通过中文分词器,将文

    2024年03月11日
    浏览(67)
  • 一种轻量级定时任务实现

    现在市面上有各式各样的分布式定时任务,每个都有其独特的特点,我们这边的项目因为一开始使用的是分布式开源调度框架TBSchedule,但是这个框架依赖ZK, 由于ZK的不稳定性和项目老旧无人维护 ,导致我们的定时任务会偶发出现异常,比如:任务停止、任务项丢失、任务不

    2024年02月14日
    浏览(48)
  • 一种轻量级websocket实现方案

    定义ws服务器工具类WsktUtil 开机启动ws服务器 测试结果 自定义一个WebSocketClient子类 测试连接ws服务器 测试效果

    2024年02月15日
    浏览(41)
  • 轻量级软件FastGithub实现稳定访问github

    当我们想访问全球最大的“同性交友网站”https://github.com/ 时,总会出现无法访问的界面,令人非常苦恼: 幸运的是,有一种轻量级的软件可以帮助我们稳定地访问GitHub,那就是FastGithub。 FastGithub是一个简洁且专一的软件,它可以帮助你稳定地访问GitHub。FastGithub通过修改本地

    2024年02月06日
    浏览(49)
  • 使用Go语言打造轻量级Web框架

    前言 Web框架是Web开发中不可或缺的组件。它们的主要目标是抽象出HTTP请求和响应的细节,使开发人员可以更专注于业务逻辑的实现。在本篇文章中,我们将使用Go语言实现一个简单的Web框架,类似于Gin框架。 功能 我们的Web框架需要实现以下功能: 路由:处理HTTP请求的路由

    2023年04月08日
    浏览(56)
  • [Netty源码] Netty轻量级对象池实现分析 (十三)

    1.对象池技术介绍 对象池其实就是缓存一些对象从而避免大量创建同一个类型的对象, 类似线程池。对象池缓存了一些已经创建好的对象, 避免需要的时候创建。同时限制了实例的个数。 池化技术最终要的就是重复的使用池内已经创建的对象。 创建对象的开销大 会创建大量的

    2023年04月18日
    浏览(47)
  • Spring Boot整合Postgres实现轻量级全文搜索

    有这样一个带有搜索功能的用户界面需求: 搜索流程如下所示: 这个需求涉及两个实体: “评分(Rating)、用户名(Username)”数据与 User 实体相关 “创建日期(create date)、观看次数(number of views)、标题(title)、正文(body)”与 Story 实体相关 需要支持的功能对 User

    2024年02月19日
    浏览(46)
  • 树莓派使用Nginx 搭建轻量级网站远程访问

    转载自cpolar极点云文章:树莓派使用Nginx 搭建轻量级网站远程访问 安装 Nginx(发音为“engine-x”)可以将您的树莓派变成一个强大的 Web 服务器,可以用于托管网站或 Web 应用程序。相比其他 Web 服务器,Nginx 的内存占用率非常低,可以在树莓派等资源受限的设备上运行。同时

    2024年02月11日
    浏览(44)
  • OpenHarmony实战开发-如何实现一个轻量级输入法应用。

    ​ 本示例使用inputMethodEngine实现一个轻量级输入法应用kikaInput,支持在运行OpenHarmony OS的智能终端上。 使用说明 1.使用hdc shell aa start ability -a InputMethod -b cn.openharmony.inputmethodchoosedialog命令拉起切换输入法弹窗,点击kikainput切换输入法到当前应用。 2.点击应用中的编辑框,拉起

    2024年04月24日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包