空心|最全分布式锁设计方案
本文涉及内容:
- 分布式锁介绍;
- 用数据表做分布式锁原理介绍 2、思路:
当执行一个方法的时候 , 我们首先尝试往表中插入一条数据 。 如果插入成功 , 则占锁成功 , 继续往下执行 , 执行完删除该记录 。 如果插入失败 , 我们再以当前方法名、当前机器ip+线程id、数据被操作时间为5分钟内(5分钟表示锁失效的时间)为条件去查询 , 如果有记录 , 表示该机器的该线程在5分钟内占有过锁了 , 直接往下执行最后删除记录;如果没有记录 , 占有锁失败 。 一个用户就是一个线程 , 所以我们可以把机器ip和用户id组合一起当成dl_device_info 。
3、占有锁和释放锁:
- 占有锁:
INSERT INTO tb_distributed_lock ( dl_method_name, dl_device_info)VALUES ('方法名', 'ip如果insert失败 , 则:
SELECT count(*)FROM tb_distributed_lockWHERE dl_method_name = '方法名'AND dl_device_info = 'ip- 释放锁:
DELETEFROM tb_distributed_lockWHERE dl_method_name = '方法名'AND dl_device_info = 'ip4、小总结:
以上表结构可能并不是很好 , 只是提供了这么一个思路 。 下面说它的优缺点:
- 优点:成本低 , 不需要引入其他的技术
- 缺点:对数据库依赖性强 , 如果数据库挂了 , 那就凉凉了 , 所以数据库最好也是高可用的
基于redis的set key value nx ex 30 , 这条语句的意思就是如果key不存在就设置 , 并且过期时间为30s , 如果key已经存在就会返回false 。 如果要以毫秒为单位 , 把ex换成px就好了 。 我们执行方法前 , 先将方法名当成key , 执行这条语句 , 如果执行成功就是获取锁成功 , 执行失败就是获取锁失败 。
2、代码实现:
- RedisUtil的部分代码:
/*** key不存在时就设置 , 返回true , key已存在就返回false* @param key* @param value* @param timeout* @return*/public static boolean setIfAbsent(String key, String value, Long timeout) { return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);}/*** 获取key-value* @param key* @return*/public static String getString(String key) { return (String) redisTemplate.opsForValue().get(key);}/*** 删除key* @param key* @return*/public static boolean delKey(String key) { return redisTemplate.delete(key);}- 业务方法中使用:
public String hello() { // 方法名当作key String key = "hello"; String value = "http://kandian.youth.cn/index/hellolock"; if (RedisUtil.setIfAbsent(key, value, 60 * 2L)) {System.out.println("成功获取到锁 , 开始执行业务逻辑……");// 假如执行业务逻辑需要1分钟try {TimeUnit.MINUTES.sleep(1L); } catch (Exception e) { e.printStackTrace();};// 释放锁先校验value , 避免释放错if (value.equals(RedisUtil.getString(key))) {RedisUtil.delKey(key);System.out.println("执行完业务逻辑 , 释放锁成功");}return "success"; } else {System.out.println("锁被别的线程占有 , 获取锁失败");return "acquire lock failed"; }}3、小总结:
- 优点:简单易用 , 一条redis命令就搞定 。 可以设置过期时间 , 避免释放锁失败造成其他线程长时间无法获取锁的问题 。
- 缺点:这种做法只适合redis是单机的时候 , 如果redis有集群 , 这样做就会出问题 。 假如一个线程在master上获取锁成功了 , 在master还没来得及将数据同步到slave上的时候 , master挂了 , slave升级为master 。 第二个线程进来尝试获取锁 , 因为新的master上并没有这个key , 所以 , 也能成功获取到锁 。
推荐阅读
- 一味宠爱|最全盘点卡中国脖子的35项技术,折射中国工业水平的真实现状
- 空心|招聘丨山西千沐云物联科技有限公司
- 德国天然宠粮Real Nature浩瀚母公司Fressnapf(宠爱碗)最全剖析
- 空心|记 Arthas 实现一次 CPU 排查与代码热更新
- 空心|realme 真我X7系列凭什么成为2020年度爆款旗舰?
- 空心|打响芯片突围战!中科院出手,全面去除西方技术
- 半导体|新风口!第三代半导体写入十四五规划,最全概念股盘点!(名单)
- |“空心化”难解决,专家推崇“合村并镇”!老农:2点疑虑先解答
- 空心|#新闻拍一拍#Debian项目曾讨论永久禁止Linus出席
- 数码小王|单机、分布式、集群的区别与联系
