利用redis实现分布式锁知识点总结及相关改进
利用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实现分布式锁知识点总结及相关改进的更多相关文章
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- 【Redis】利用 Redis 实现分布式锁
技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...
- springboot利用redis实现分布式锁(redis为单机模式)
1.pom文件添加redis支持 <dependency> <groupId>org.springframework.boot</groupId> <arti ...
- spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...
- 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存
原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...
- 利用redis实现分布式事务锁,解决高并发环境下库存扣减
利用redis实现分布式事务锁,解决高并发环境下库存扣减 问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...
- 基于redis的分布式锁的分析与实践
前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...
- 基于redis的分布式锁二种应用场景
“分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种.具体到业务场景中,我们要考虑二种情况: 一.抢不到锁的请求,允许丢弃(即:忽略) ...
- 利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析 一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...
随机推荐
- C++指针速记
基本原则:指针类型变量存储的就是地址! 1.数组名就是数组首元素的地址** int age[3]; int* p = age; 2.使用new操作符实际上是向操作系统申请一块内存(包含类型信息),返回 ...
- Python【每日一问】13
问:请简述一下python的GIL 答:GIL 锁,全局解释器锁,仅在CPython解释器中,作用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行.
- 使用iptables基于MAC地址进行访控
近日完成一台基于CentOS的SVN服务器配置,由于该服务器上的文件非常重要,仅部分用户需要访问,最后决定采用iptables来做访控,并且是根据MAC地址来限制,为了便于后期维护,防火墙的配置是通过 ...
- docker环境安装与开启远程访问
一,安装docker 1,服务器安装 docker yum install docker 直接yum安装版本太低 2,卸载:老版本的Docker在yum中名称为docker或docker-engine ...
- VMWare给macos虚拟机扩容方法
一开始在VMWareWorkStation上创建macos虚拟机时,我考虑到物理硬盘大小有限,只分配了34G,随着不断的使用,虚拟机消耗的虚拟磁盘逐渐增长,因磁盘空间不足而导致无法在虚拟机中使用xco ...
- RIDE创建工程和测试套件和用例--书本介绍的入门方法,自己整理实践下
1.选择File->New Project 2.弹出的New Project对话框,在Name文本框输入一个名词,如“TestProject-0805”,右侧选中“Directory”,选中建立 ...
- 【摘】Oracle执行计划不走索引的原因总结
感谢原博主 http://soft.chinabyte.com/database/364/12471864.shtml 在Oracle数据库操作中,为什么有时一个表的某个字段明明有索引,当观察一些语的 ...
- sql语句基本查询操作
表结构 SQL> desc empName Type Nullable Default Comments -------- ------------ -------- ------- ----- ...
- CentOS使用nginx部署https服务
nginx安装参考:https://www.cnblogs.com/taiyonghai/p/6728707.html 自签证书生成参考:https://gmd20.github.io/blog/op ...
- [UNITY 5.4 UGUI] 模态对话框
1.建立两个画布 a.背景界面 b.置顶界面(添加一个 panel 控件) 2.修改置顶界面中 panel ,添加属性 [Canvas Group] 3.根据界面设计情况修改透明度,色彩,图片