基于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.   

单元测试

  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.    

优化建议

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

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

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

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

(0)
运维的头像运维
上一篇2025-05-26 21:28
下一篇 2025-05-26 21:29

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

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