热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分布式共享锁的设计

|date:20190410功能介绍针对某种资源,需要被整个系统的各台服务器共享访问,但是只允许一台服务器同时访问。比如说订单服务是做成

| date: 20190410

功能介绍


针对某种资源,需要被整个系统的各台服务器共享访问,但是只允许一台服务器同时访问。比如说订单服务是做成集群的,当两个以上结点同时收到一个相同订单的创建指令,这时并发就产生了,系统就会重复创建订单。而分布式共享锁就是解决这类问题。

##流程图
在这里插入图片描述

代码实现

/*** @Author feizhou* @Description 分布式锁模板* @Date 10:39 2019/4/9* @Param [key, actionLog, expireSecond]* @return java.lang.Boolean**/
public static Boolean distributedLock_v2(String key,String actionLog, long milliseconds,boolean isDelLock){RedisBaseDao redisDao = RedisUtil.getRedisDao();boolean isGetLock=false;String requestId = UUID.randomUUID().toString();try {isGetLock = redisDao.getDistributedLock(key,requestId , milliseconds);if(!isGetLock){logger.error("分布式锁拦截,不能重复操作,"+key+",actionLog="+actionLog);}return isGetLock;} catch (Exception e) {e.printStackTrace();if(e instanceof RedisException){logger.error("redis 分布式锁异常,可能存在重复操作的的可能性,key="+key+",actionLog="+actionLog+",e="+e);return true;}}finally {if(isGetLock&&isDelLock){try {redisDao.releaseDistributedLock(key,requestId);} catch (Exception e) {e.printStackTrace();logger.error("分布式锁释放锁失败,key="+key+",actionLog="+actionLog+","+e);}}}return false;
}


/*** 尝试获取分布式锁* @param lockKey 锁* @param requestId 请求标识* @param milliseconds 超期时间* @return 是否获取成功*/private static final Long RELEASE_SUCCESS = 1L;
public boolean getDistributedLock(String lockKey, String requestId, Long milliseconds) {return this.setNx(lockKey, requestId, milliseconds);
}
/*** 释放分布式锁* @param lockKey 锁* @param requestId 请求标识* @return 是否释放成功*/
public boolean releaseDistributedLock( String lockKey, String requestId) {return this.deleteKeyForSameValue(lockKey,requestId);
}public Boolean setNx( String key, String value,Long expireTime) {Boolean isSet = redisTemplate.execute(new RedisCallback() {@Overridepublic Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {//过期时间好处:即使服务器宕机了,也能保证锁被正确释放。//setNx原子性操作,防止同一把锁在同一时间可能被不同线程获取到Jedis jedis = (Jedis) redisConnection.getNativeConnection();String result = jedis.set(key, value, "nx", "px", expireTime);if("OK".equals(result)){return true;}return false;}});return isSet;
}
public Boolean deleteKeyForSameValue( String key, String value) {return redisTemplate.execute(new RedisCallback() {@Overridepublic Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {Jedis jedis = (Jedis) redisConnection.getNativeConnection();//删除key的时候,先判断该key对应的value是否等于先前设置的随机值,只有当两者相等的时候才删除该key//防止释放其他客户端获取到的锁//原子性操作String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}});
}

方案优点


多个服务器竞争资源,需要排队,解决类似一个订单被多个服务器提交问题。


方案缺点


  • 试用与一主多从的redis集群,如果多主多从,不能解决共享锁问题
    -这个问题解决方案https://yq.aliyun.com/articles/674394,https://blog.csdn.net/chen_kkw/article/details/81433470
  • 同时当一主多从服务器,主机宕机,有丢失锁的风险,概率很小。
    • 场景
    • 在Redis的master节点上拿到了锁,但是这个加锁的key还没有同步到slave节点,master故障,发生故障转移,slave节点升级为master节点; 导致锁丢失。概率很小,可以不考虑。

待改善点


对待完善点进行列举,以便后续改进


其他说明


推荐阅读
  • Hadoop集群搭建:实现SSH无密码登录
    本文介绍了如何在CentOS 7 64位操作系统环境下配置Hadoop集群中的SSH无密码登录,包括环境准备、用户创建、密钥生成及配置等步骤。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 个人博客:打开链接依赖倒置原则定义依赖倒置原则(DependenceInversionPrinciple,DIP)定义如下:Highlevelmo ... [详细]
  • 本文基于Java官方文档进行了适当修改,旨在介绍如何实现一个能够同时处理多个客户端请求的服务端程序。在前文中,我们探讨了单客户端访问的服务端实现,而本篇将深入讲解多客户端环境下的服务端设计与实现。 ... [详细]
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • 观察到在首次执行设置范围内的随机值分配时,结果倾向于靠近设定的最小值和最大值。 ... [详细]
  • UVa 11683: 激光雕刻技术解析
    自1958年发明以来,激光技术已在众多领域得到广泛应用,包括电子设备、医疗手术工具、武器等。本文将探讨如何使用激光技术进行材料雕刻,并通过编程解决一个具体的激光雕刻问题。 ... [详细]
  • 本文详细探讨了 Android Service 组件中 onStartCommand 方法的四种不同返回值及其应用场景。Service 可以在后台执行长时间的操作,无需提供用户界面,支持通过启动和绑定两种方式创建。 ... [详细]
  • iOS如何实现手势
    这篇文章主要为大家展示了“iOS如何实现手势”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“iOS ... [详细]
  • 本文旨在探讨Swift中的Closure与Objective-C中的Block之间的区别与联系,通过定义、使用方式以及外部变量捕获等方面的比较,帮助开发者更好地理解这两种机制的特点及应用场景。 ... [详细]
  • 本文探讨了如何利用 Android 的 Movie 类来展示 GIF 动画,并详细介绍了调整 GIF 尺寸以适应不同布局的方法。同时,提供了相关的代码示例和注意事项。 ... [详细]
  • 一、使用Microsoft.Office.Interop.Excel.DLL需要安装Office代码如下:2publicstaticboolExportExcel(S ... [详细]
  • 汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ... [详细]
  • 本报告记录了嵌入式软件设计课程中的第二次实验,主要探讨了使用KEIL V5开发环境和ST固件库进行GPIO控制及按键响应编程的方法。通过实际操作,加深了对嵌入式系统硬件接口编程的理解。 ... [详细]
  • 探讨 try-finally 结构中 finally 块的执行情况
    本文深入分析了 Java 中 try-finally 结构的执行机制,特别是探讨了在不同情况下 finally 块是否会得到执行。 ... [详细]
author-avatar
心胸宽大的榛子lcf
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有