利用redis实现分布式锁知识点总结及相关改进

先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/8003838.html

@frameStart@

@frameTitle@最新修改@frameTitle@

老版问题:lock时如果只用jedis.set(String key, String value, String nxxx, String expx, int time)方法存在若干问题:1.不支持重入锁,2.且超时时间的设置也是一个问题

解决方案:1. 锁的结构用hash,因为string形式无法支持可重入;

2.  使用了hash就不能再用jedis.set(String key, String value, String nxxx, String expx, int time)这个方法了,所以取锁也要使用eval表达式。

hash数据结构:

 bizKey:{   // 某个业务锁
  clientId:“”,// 业务id,唯一;
state:1, //取锁次数,用来实现可重入
// 超时时间直接用expire来表示,用字段的话不安全。
}

伪代码如下:

加锁基本思路: 判断锁是否存在,如果不存在,直接加锁;如果存在,则判断client是否与当前业务id一致,如果一致,加锁成功,state+1,否则提示加锁失败

去锁基本思路:判断锁是否存在,如果不存在,直接返回成功;如果client不一致,返回失败;now = state-1,如果now=0,直接删掉锁。返回成功。

最后,关于超时时间的问题:如果不设超时的话,业务异常导致来不及解锁时会导致数据一直存在。如果设的话,设的太小了,可能业务处理时间太长,别的线程在锁过期后会取到锁,此方式最不可取。如果设的时间太长,与不设同义。

方案:?

关于锁超时的俩种言论,参考一下:

一种:

使用 WATCH/MULTI/EXEC ,watch能保证 MULTI 和 EXEC 之间的命令只有在watch的值没有变化才执行成功,见官方文档https://redis.io/topics/trans...

所以一般这个锁的值要在整个系统保持唯一。

另一种:

锁超时被释放不是很正常吗。。 因为我没有用过redis,所以对于楼上说的超时如何避免我不知道。。

但是从分布式系统的角度来分析这个问题,锁其实就等于租约,谁从redis得到了租约,谁就是集群的leader,执行一些follower不能做的操作,

但是呢,leader总是会由于种种问题(网络、gc)无法及时续租,导致超时,这时候另外一个follower进而得到锁,导致集群双主。

所以问题的性质就变成了分布式情况下如何避免多主(或脑裂)。常用的做法就是fencing机制,如kafka的epoch。楼主可以试下

@frameEnd@

1.redis基础知识点:

  1.1 多线程环境下,多条命令不具备原子性,尽量使用单命令或eval表达式;

  1.2 redis天然单线程,化异步为同步,处理效率极高;且一般内网操作,速度比较快;支持多机部署,用来实现锁机制十分合适;

2. 针对锁的基本特性,利用redis的特点解决之
  2.1互斥性:set一个key NX 观看返回值即可
  2.2 防死锁:设置key的过期时间即可
  2.3 容错性:使用Redisson实现分布式锁
  2.4 排他性:set key value时,value设置一个独一无二的值如uuid
  针对以上几个特性,
  **获取锁**:
    使用jedis.set(key, value_uuid, NX, PX, 10000);即可实现取锁;
  **释放锁**:
    使用eval表达式即可:
    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));
  **存在问题**

    问题1:锁超时时间大小不好设置,因为业务处理的时间大小不确定,可能会很长,长到超时时间满足不了。

    问题2:关于拿锁是重试还是排队拿锁?可以自己参考AQS类,锁的本质就是一个状态的获得,AQS类是JVM中state变量的获取,而基于redis的分布式锁则是内存中变量的获取,redis已经天然的变异步为同步了,所以只能排队拿锁,如果恰好每次重试的过程中都是被其它客户端持有锁的,极有可能造成线程长时间拿不到锁(即使你忙循环调用redis,redis也不会单独优先处理你的)

  2.5 可重入:不支持,重置有效期是错误的方式;另外value_uuid被设定成了固定值(用来排他),无法像AQS的state字段那样增长或者减少。

  2.6 总结:排他和可重入似乎不能同时实现。而且实现了可重入,不支持排他,这个锁机制也是不可用的。所以,放弃可重入

利用redis实现分布式锁知识点总结及相关改进的更多相关文章

  1. 利用redis实现分布式锁

    分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...

  2. 【Redis】利用 Redis 实现分布式锁

    技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...

  3. springboot利用redis实现分布式锁(redis为单机模式)

    1.pom文件添加redis支持 <dependency> <groupId>org.springframework.boot</groupId> <arti ...

  4. spring boot 利用redisson实现redis的分布式锁

    原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...

  5. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  6. 利用redis实现分布式事务锁,解决高并发环境下库存扣减

    利用redis实现分布式事务锁,解决高并发环境下库存扣减   问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...

  7. 基于redis的分布式锁的分析与实践

    ​ 前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...

  8. 基于redis的分布式锁二种应用场景

    “分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种.具体到业务场景中,我们要考虑二种情况: 一.抢不到锁的请求,允许丢弃(即:忽略) ...

  9. 利用多写Redis实现分布式锁原理与实现分析(转)

    利用多写Redis实现分布式锁原理与实现分析   一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...

随机推荐

  1. soapui的简单使用

    工具下载地址:https://www.soapui.org/downloads/soapui.html 名词解释 https://www.cnblogs.com/fcfblog/p/5830205.h ...

  2. prepareRefresh()方法源码探究

    该方法目的是做刷新上下文前的准备工作: 首先清空bean扫描器map中的内容,然后调用父类的prepareRefresh方法: 父类的准备刷新方法,主要做了3个工作: 1.简单的标志赋值----> ...

  3. 使用摄像头或视频运行 ORB-SLAM2 SLAM14讲 第一次课后作业

    参考:视觉SLAM十四讲(第一章作业) 深蓝上高博的第一讲课后题: 题目:6 * 使用摄像头或视频运行 ORB-SLAM2(3 分,约 1 小时)请注意本题为附加题.了解⼀样东西最快的⽅式是⾃⼰上⼿使 ...

  4. idea properties文件中文无法正常显示

    引用:https://blog.csdn.net/u010999809/article/details/81204457 问题:在idea打开配置文件,已经设置了全局编码格式为UTF-8,和项目编码格 ...

  5. HTML怎么实现字体加粗

    HTML的加粗标签是<b>标签,是用来对你自定文字加粗,写法如下: 字体加粗:<b>这里是加粗的内容</b> 这样就可以实现加粗了!

  6. Spring-MVC配置思路

    前言: Spring-mvc是一个解决页面代码和后台代码分离的框架. 在没有配置servlet在服务器启动时就创建被创建时,总是当请求过来了servlet对象才会被创建 因此先从请求开始. 为了给每一 ...

  7. 学习MeteoInfo二次开发教程(十二)

    1.添加新的Form窗体: 在解决方案资源管理器中,右键MeteoInfoDemo,“添加”,“Windows 窗体” 2.新窗体中添加好layersLegend1和Layout之后,要把layers ...

  8. c语言函数参数类似继承的传递

    函数的参数如果是一个父结构的指针, 这个结构包含在另一个子结构中, typedef struct test_node_one test_node_one_t; typedef struct test_ ...

  9. React面试题

    React 简述下React的生命周期,性能优化在哪个生命周期,ajax操作在哪个生命周期 React中key的作用是什么 什么是虚拟DOM diff算法原理 React中refs的作用是什么

  10. C# 反射获取属性类型及属性值,两个实体转换

    一.两个实体数据转换 /// <summary> /// 为属性赋值 /// </summary> /// <typeparam name="T"&g ...