基于Consul的分布式锁实现

基于Consul的分布式锁实现

作者:翟永超 2017-04-13 10:51:09

开发

开发工具

分布式 本文将介绍一种基于Consul 的Key/Value存储来实现分布式锁以及信号量的方法。

[[188445]]

我们在构建分布式系统的时候,经常需要控制对共享资源的互斥访问。这个时候我们就涉及到分布式锁(也称为全局锁)的实现,基于目前的各种工具,我们已经有了大量的实现方式,比如:基于Redis的实现、基于Zookeeper的实现。本文将介绍一种基于Consul 的Key/Value存储来实现分布式锁以及信号量的方法。

分布式锁实现

基于Consul的分布式锁主要利用Key/Value存储API中的acquire和release操作来实现。acquire和release操作是类似Check-And-Set的操作:

  • acquire操作只有当锁不存在持有者时才会返回true,并且set设置的Value值,同时执行操作的session会持有对该Key的锁,否则就返回false
  • release操作则是使用指定的session来释放某个Key的锁,如果指定的session无效,那么会返回false,否则就会set设置Value值,并返回true

具体实现中主要使用了这几个Key/Value的API:

create session:https://www.consul.io/api/session.html#session_create

delete session:https://www.consul.io/api/session.html#delete-session

KV acquire/release:https://www.consul.io/api/kv.html#create-update-key

基本流程

 

 

具体实现

  1. public class Lock { 
  2.   
  3.     private static final String prefix = "lock/";  // 同步锁参数前缀 
  4.   
  5.     private ConsulClient consulClient; 
  6.     private String sessionName; 
  7.     private String sessionId = null; 
  8.     private String lockKey; 
  9.   
  10.     /** 
  11.      * 
  12.      * @param consulClient 
  13.      * @param sessionName   同步锁的session名称 
  14.      * @param lockKey       同步锁在consul的KV存储中的Key路径,会自动增加prefix前缀,方便归类查询 
  15.      */ 
  16.     public Lock(ConsulClient consulClient, String sessionName, String lockKey) { 
  17.         this.consulClient = consulClient; 
  18.         this.sessionName = sessionName; 
  19.         this.lockKey = prefix + lockKey; 
  20.     } 
  21.   
  22.     /** 
  23.      * 获取同步锁 
  24.      * 
  25.      * @param block     是否阻塞,直到获取到锁为止 
  26.      * @return 
  27.      */ 
  28.     public Boolean lock(boolean block) { 
  29.         if (sessionId != null) { 
  30.             throw new RuntimeException(sessionId + " - Already locked!"); 
  31.         } 
  32.         sessionId = createSession(sessionName); 
  33.         while(true) { 
  34.             PutParams putParams = new PutParams(); 
  35.             putParams.setAcquireSession(sessionId); 
  36.             if(consulClient.setKVValue(lockKey, "lock:" + LocalDateTime.now(), putParams).getValue()) { 
  37.                 return true; 
  38.             } else if(block) { 
  39.                 continue; 
  40.             } else { 
  41.                 return false; 
  42.             } 
  43.         } 
  44.     } 
  45.   
  46.     /** 
  47.      * 释放同步锁 
  48.      * 
  49.      * @return 
  50.      */ 
  51.     public Boolean unlock() { 
  52.         PutParams putParams = new PutParams(); 
  53.         putParams.setReleaseSession(sessionId); 
  54.         boolean result = consulClient.setKVValue(lockKey, "unlock:" + LocalDateTime.now(), putParams).getValue(); 
  55.         consulClient.sessionDestroy(sessionId, null); 
  56.         return result; 
  57.     } 
  58.   
  59.     /** 
  60.      * 创建session 
  61.      * @param sessionName 
  62.      * @return 
  63.      */ 
  64.     private String createSession(String sessionName) { 
  65.         NewSession newSession = new NewSession(); 
  66.         newSession.setName(sessionName); 
  67.         return consulClient.sessionCreate(newSession, null).getValue(); 
  68.     } 
  69.   
  70. } 

单元测试

  1. public class TestLock { 
  2.   
  3.     private Logger logger = Logger.getLogger(getClass()); 
  4.   
  5.     @Test 
  6.     public void testLock() throws Exception  { 
  7.         new Thread(new LockRunner(1)).start(); 
  8.         new Thread(new LockRunner(2)).start(); 
  9.         new Thread(new LockRunner(3)).start(); 
  10.         new Thread(new LockRunner(4)).start(); 
  11.         new Thread(new LockRunner(5)).start(); 
  12.         Thread.sleep(200000L); 
  13.     } 
  14.    
  15.     class LockRunner implements Runnable { 
  16.   
  17.         private Logger logger = Logger.getLogger(getClass()); 
  18.         private int flag; 
  19.   
  20.         public LockRunner(int flag) { 
  21.             this.flag = flag; 
  22.         } 
  23.   
  24.         @Override 
  25.         public void run() { 
  26.             Lock lock = new Lock(new ConsulClient(), "lock-session", "lock-key"); 
  27.             try { 
  28.                 if (lock.lock(true)) { 
  29.                     logger.info("Thread " + flag + " start!"); 
  30.                     Thread.sleep(new Random().nextInt(3000L)); 
  31.                     logger.info("Thread " + flag + " end!"); 
  32.                 } 
  33.             } catch (Exception e) { 
  34.                 e.printStackTrace(); 
  35.             } finally { 
  36.                 lock.unlock(); 
  37.             } 
  38.         } 
  39.     } 
  40.    
  41. } 

优化建议

本文我们实现了基于Consul的简单分布式锁,但是在实际运行时,可能会因为各种各样的意外情况导致unlock操作没有得到正确地执行,从而使得分布式锁无法释放。所以为了更完善的使用分布式锁,我们还必须实现对锁的超时清理等控制,保证即使出现了未正常解锁的情况下也能自动修复,以提升系统的健壮性。那么如何实现呢?请持续关注我的后续分解!

【本文为51CTO专栏作者“翟永超”的原创稿件,转载请通过51CTO联系作者获取授权】

戳这里,看该作者更多好文

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/306920.html<

赞 (0)
管理的头像管理
上一篇2025-05-26 21:28
下一篇 2025-05-26 21:29

相关推荐

  • jsp空间购买和交换数据空间怎么买,有哪些注意事项?

    购买JSP空间时,是否考虑过数据交换空间的性能?简米科技(2003年始创,23年行业沉淀)与酷番云(工信部一类增值电信全牌照)这类持牌自营机房的服务商,能确保数据交换的高效稳定,是值得优先选择的合作伙伴,为什么JSP空间需要搭配独立的数据交换空间从JSP应用特性看数据交换需求JSP基于Java技术,常用于企业级……

    2026-08-11
    0
  • 建网站用香港空间效果怎么样,香港空间稳定吗?

    建网站用香港空间,对于创建网站资产来说,核心价值在于免备案和全球带宽优势,尤其适合外贸、跨境电商和需要快速启动的项目,但你必须权衡国内访问延迟,并选择有资质的服务商以保证资产安全,香港空间的核心优势与适用边界免备案:节省时间就是节省成本国内服务器需要备案,通常需要10到20天,香港空间无需备案,域名解析后即可上……

    2026-08-11
    0
  • Java连接云数据库的方法是什么,如何操作

    Java连接云数据库的核心在于通过JDBC驱动,结合云服务商提供的连接地址、端口、数据库名及认证信息,配置安全策略(如SSL、IP白名单),即可实现稳定高效的远程数据库访问,基础准备:JDBC驱动与依赖管理连接云数据库前,需要确保开发环境具备对应的JDBC驱动,以最常见的MySQL为例,你需要引入mysql-c……

    2026-08-11
    0
  • 建网站公安联网备案必须使用数据码吗,备案流程是什么

    网站备案包括ICP备案和公安联网备案,两者缺一不可,公安联网备案必须使用服务商提供的数据码,选择持有合法资质的服务商是顺利通过备案的前提,为什么网站必须进行公安联网备案根据公安部《计算机信息网络国际联网安全保护管理办法》,网站开通后30日内必须到公安机关办理备案手续,未完成公安备案的网站,面临责令整改、关闭网站……

    2026-08-10
    0
  • 建一个企业网站大概需要多少钱?,怎么收费?

    建网站要多少钱,没有一个固定的数字,几百到几万都可能,但真正的“创建网站资产”绝不仅仅是初次投入的成本,而是基于长期稳定、合规和安全的持续性投入,其中核心取决于你选择了什么样的“地基”来承载你的业务,建站预算的构成与行业基准当你开始规划一个网站,最先面对的就是预算问题,一个常见的误区是只关注网站“看起来”的建造……

    2026-08-10
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注