基于Redis的简单分布式锁的原理
参考资料:https://redis.io/commands/setnx
加锁是为了解决多线程的资源共享问题。Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的加锁机制。但是到了分布式环境,单机环境中的锁就没什么作用了,因为每个节点只能获取到自己机器内存中的锁,而无法获取到其他节点的锁状态。
分布式环境中,应该用专门的分布式锁来解决需要加锁的问题。分布式锁有很多实现,Redis,zookeeper都可以。这里以Redis为例,讲述一下基于Redis的分布式锁的基本原理。
用Redis来实现分布式锁的原因
不同的节点无法获取到其他节点内存中的锁,但是大家都可以获取到Redis中的资源,所以这是实现分布式锁的基础-所有节点都可以同时获取到redis的状态。
而具体的实现,则是基于两个redis的命令-SETNX和GETSET。
SETNX:SET if Not eXists,格式为SETNX key value,仅当key不存在时才会设置成功,返回1,否则返回0。这是加锁的基础,假设key名为lock.foo,只要有一个线程设置成功,那其他线程都无法再设置。
GETSET:GETSET key value,返回旧值,并将新的值设置进去。这个的作用后面会讲到。
锁实现以及超时设计
加锁方式很简单,在线程中对redis发送一个命令:
SETNX lock.foo <current Unix time + lock timeout + 1>
线程A调用setnx命令,设置key为lock.foo(所有线程要用同样的key,否则就不是一个锁了),值为current Unix time + lock timeout + 1,即当前时间加上加锁时长,最终的值也就是过期时间。如果A对锁的持有结束,则可自行调用del lock.foo来释放锁。
A持有锁的过程中线程B在调用命令SETNX lock.foo,会得到返回值0,这说明这个锁已经被其他线程获取,这时B应该去获取lock.foo的值,看看是否小于当前时间,如果大于则锁未过期,B需要继续循环等待检查或者做其他操作;如果小于则锁已过期,B可以用del lock.foo方法去删除锁,然后在SETNX lock.foo 来获取锁。
这样就完成了分布式锁的最基本的模型,并且避免了因A线程挂掉无法释放锁而导致的死锁问题。
存在的问题
上一节的实现看上去大致还是那么回事,成功的加上锁了,还引入了超时机制。不过,GETSET还没用呢,这肯定还没完呢。请看以下场景:
A获取到了锁,但是挂掉了;
B和C都检测到A的锁超时;
B发出del lock.foo指令,删除A的锁,再setnx,获取到了锁;
C也发出del lock.foo指令,此时删除的是B的锁,然后再setnx,获取到了锁。
这个时候你会发现,B和C同时获取到了锁。这问题就大了去了。
为了解决这个问题,GETSET就起到他自己的作用了。下面用修正后的方法来重新描述一下上面的场景:
A获取到了锁,但是挂掉了;
B和C都检测到A的锁超时;
此时B不会执行del操作,而是执行:
GETSET lock.foo <current Unix timestamp + lock timeout + 1>
这个命令会给lock.foo设置新值,然后获取到老的value。这个时候B会对老的value进行检测,如果value大于当前时间,则说明这个锁已经被其他线程再次获取了,那B就会继续
等待,而不是获取锁。如果value小于当前时间,那B就可以获取到锁。
假设C获取到锁,然后B又再次调用GETSET方法,那也不会对C持有锁造成影响,不过确实会将超时时间延长一些。但是出现这个情况肯定是B和C都在之前检测到了锁超时,说明这两个线程对锁的访问肯定较为接近,所以这里如果要求不是太严格也可以忽略。
基本原理就这些,代码稍后奉上。
基于Redis的简单分布式锁的原理的更多相关文章
- 基于redis实现的分布式锁
基于redis实现的分布式锁 我们知道,在多线程环境中,锁是实现共享资源互斥访问的重要机制,以保证任何时刻只有一个线程在访问共享资源.锁的基本原理是:用一个状态值表示锁,对锁的占用和释放通过状态值来标 ...
- 使用Redis模拟简单分布式锁,解决单点故障的问题
需求描述: 最近做一个项目,项目中有一个功能,每天定时(凌晨1点)从数据库中获取需要爬虫的URL,并发送到对应的队列中,然后客户端监听对应的队列,然后执行任务.如果同时部署多个定时任务节点的话,每个节 ...
- 基于 Redis 实现简单的分布式锁
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- 基于Redis实现简单的分布式锁【理论】
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- Redlock(redis分布式锁)原理分析
Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...
- Redis分布式锁的原理和实现
前言 我们之前聊过redis的,对基础不了解的可以移步查看一下: 几分钟搞定redis存储session共享--设计实现:https://www.cnblogs.com/xiongze520/p/10 ...
- Redis系列(二)--分布式锁、分布式ID简单实现及思路
分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...
- redis客户端、分布式锁及数据一致性
Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...
- Redisson 实现分布式锁的原理分析
写在前面 在了解分布式锁具体实现方案之前,我们应该先思考一下使用分布式锁必须要考虑的一些问题. 互斥性:在任意时刻,只能有一个进程持有锁. 防死锁:即使有一个进程在持有锁的期间崩溃而未能主动释放锁, ...
随机推荐
- C/C++语言简介之关键字
关键字又称为保留字,就是已被C语言本身使用,不能作其它用途使用的字.例如关键字不能用作变量名.函数名等标识符.由ISO标准定义的C语言关键字共32个:auto.double.int.struct.br ...
- 箱型图boxplot函数的使用
主要参数: medlwd:设置中位线宽度 whiskcol:设置虚线颜色 staplecol:设置顶端颜色 outcol:离群值颜色 相应的具体位置: outline=FALSE:去除离群值 outp ...
- MysqL 磁盘写入策略之innodb_flush_log_at_trx_commit
本文从参数含义,性能,安全角度阐述两个参数为不同的值时对db 性能,数据的影响,引擎是Innodb的前提下. 取值:0/1/2 innodb_flush_log_at_trx_commit=0,表示每 ...
- 两种简单的方法Docker构建LANMP
在初步入门学习Docker的过程中一步步了解了Docker容器在团队开发中所起到的作用,一边学习一边操作基本命令,当然到现在还处于一个擦边的入门阶段. 尝试一下用Docker构建一个集成开发环境. S ...
- PHP 支持加解密的函数
function encrypt($string,$operation,$key=''){ $key=md5($key); $key_length=strlen($key); $string=$ope ...
- python_crawler,批量下载文件
这个第一个python3网络爬虫,参考书籍是<python网络数据采集>.该爬虫的主要功能是爬取某个网站,并将.rar,.doc,.docx,.zip文件批量下载. 后期将要改进的是,用后 ...
- AssetBundle实现服务器下载并从本地读取
废话不多说 直接上代码. 从服务器下载的, 很简单 private IEnumerator Start() { byte[] ab = null; int len = 0; WWW www =nul ...
- Linux OpenSSH后门的添加与防范
引言:相对于Windows,Linux操作系统的密码较难获取.不过很多Linux服务器配置了OpenSSH服务,在获取root权限的情况下,可以通过修改或者更新OpenSSH代码等方法,截取并保存其S ...
- Davinci DM6446开发攻略——linux-2.6.18移植
TI DAVINCI 使用最新的内核是montavista linux-2.6.18,之前说过,国内很多公司,包括开发板的软件包,一直在使用montavista linux-2.6.10,这个版本准 ...
- 图像采集系统的Camera Link标准接口设计
高速数据采集系统可对相机采集得到的实时图像进行传输.实时处理,同时实现视频采集卡和计算机之间的通信.系统连接相机的接口用的是Camera Link接口,通过Camera Link接口把实时图像高速传输 ...