[Re:从零开始的分布式] 0.x——Reids实现分布式锁
上节提到了,分布式锁通常应满足如下要求,互斥性、高可用、高效率、可重入、锁失效这五个基本原则。由于Redis自身“快”的特点,所以高效率可以看作满足。
下文在单机情况下与多机情况下,对利用Redis实现分布式锁做出了阐述。
单机Redis分布式锁
由于Redis本身的单线程特性,所以可以采用设置一个值的方式进行分布式锁。通常采用SETNX(set if not exist),进行设置,对资源使用完毕后,使用DEL进行删除。可以根据SETNX的返回值得到,是否成功获得锁,这一定程度上实现了互斥性,代码如下:
SETNX lock 1
...do something
DEL lock
但这时可能会存在一个问题,如果当前机器在do something的时候宕机,锁不能得到释放,导致系统死锁,所以这里需要锁失效机制,通常的锁失效,是通过设置过期时间完成的,即,
SETNX lock 1
EXPIRE lock 5
...do something
DEL lock
注意,常见面试题出现。Redis这样设置分布式锁是正确的吗?答案显然是否定的,因为 SETNX 与 EXPIRE 是两条指令,如果中间发生了宕机,同样会导致死锁。所以这里需要一条原子性的指令完成,SET指令提供了expire参数,这里利用这个参数进行完成。
SET lock 1 ex 5 nx
...do something
DEL lock
但是这样还存在问题,考虑如下情景:
1. A设置了一个锁,但是工作还没完成,锁超时释放了。
2. 此时B申请锁,由于超时释放,申请到了锁。
这导致了目前可以有A、B同时访问资源。
所以,考虑如下情形,应当在锁快失效时,更新失效时间。
但这还存在问题,存在全局时钟依赖的问题,比如Redis和客户端的时钟不一致,仍会导致问题。但目前依赖于时钟的具有自动释放锁的分布式锁都没办解决这个问题,不过由于发生概率很小,所以可以不做考虑。
关于可重入锁实现,可以通过利用Java的ThreadLocal工具,在客户端进行操作。lock时对“入锁值”+1;unlock时对"入锁值"-1,如果"入锁值"等于0,则从redis中释放锁。
多机Redis分布式锁
多机Redis分布式锁,Redis采用了RedLock对其进行实现,并在redisson中进行了实现。RedLock主要步骤如下:
- 取得当前时间
- 使用上文提到的方法依次获取N个节点的Redis锁。
- 如果获取到的锁的数量大于 (N/2+1)个,且获取的时间小于锁的有效时间(lock validity time)就认为获取到了一个有效的锁。锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。
- 如果获取锁的数量小于 (N/2+1),或者在锁的有效时间(lock validity time)内没有获取到足够的说,就认为获取锁失败。这个时候需要向所有节点发送释放锁的消息。
但Martin对这提出了质疑:

- 如果 Client 1 在持有锁的时候,发生了一次很长时间的 FGC 超过了锁的过期时间。锁就被释放了。
- 这个时候 Client 2 又获得了一把锁,提交数据。
- 这个时候 Client 1 从 FGC 中苏醒过来了,又一次提交数据。
此时,数据发生了错误。
并且,Martin同时指出,RedLock是一个严格依赖于全局时钟的系统。
- Client 1 从 A、B、D、E五个节点中,获取了 A、B、C三个节点获取到锁,我们认为它持有了锁。
- 这个时候,由于 B 的系统时间比别的系统走得快,B就会先于其他两个节点优先释放锁。
- Clinet 2 可以从 B、D、E三个节点获取到锁。在整个分布式系统就造成 两个 Client 同时持有锁了。
所以,可以看出,Redis适用于实现高可用的分布式锁。但是对于需要在保证可用性的同时,数据正确性也需要严格保证时,并不适用于实现分布式锁。
[Re:从零开始的分布式] 0.x——Reids实现分布式锁的更多相关文章
- SpringBoot开发案例从0到1构建分布式秒杀系统
前言 最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...
- hadoop 0.20.2伪分布式安装详解
adoop 0.20.2伪分布式安装详解 hadoop有三种运行模式: 伪分布式不需要安装虚拟机,在同一台机器上同时启动5个进程,模拟分布式. 完全分布式至少有3个节点,其中一个做master,运行名 ...
- 从零开始搭建Vue2.0项目(一)之快速开始
从零开始搭建Vue2.0项目(一)之项目快速开始 前言 该样板适用于大型,严肃的项目,并假定您对Webpack和有所了解vue-loader.确保还阅读vue-loader的文档,了解常见的工作流程配 ...
- 分布式改造剧集2---DIY分布式锁
前言: 好了,终于又开始播放分布式改造剧集了.前面一集中(http://www.cnblogs.com/Kidezyq/p/8748961.html)我们DIY了一个Hessian转发实现,最后我 ...
- Zookeeper系列二:分布式架构详解、分布式技术详解、分布式事务
一.分布式架构详解 1.分布式发展历程 1.1 单点集中式 特点:App.DB.FileServer都部署在一台机器上.并且访问请求量较少 1.2 应用服务和数据服务拆分 特点:App.DB.Fi ...
- 搞懂分布式技术3:初探分布式协调服务zookeeper
搞懂分布式技术3:初探分布式协调服务zookeeper 1.Zookeepr是什么 Zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/订阅,负载均衡, ...
- 分布式事务(4)---RocketMQ实现分布式事务项目
RocketMQ实现分布式事务 有关RocketMQ实现分布式事务前面写了一篇博客 1.RocketMQ实现分布式事务原理 下面就这个项目做个整体简单介绍,并在文字最下方附上项目Github地址. 一 ...
- 冰河开源了全网首个完全开源的分布式全局有序序列号(分布式ID)框架!!
写在前面 mykit-serial框架的设计参考了李艳鹏大佬开源的vesta框架,并彻底重构了vesta框架,借鉴了雪花算法(SnowFlake)的思想,并在此基础上进行了全面升级和优化.支持嵌入式( ...
- [源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架
[源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架 目录 [源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架 0x00 摘要 0 ...
随机推荐
- Executing a Finite-Length Task in the Background
[Executing a Finite-Length Task in the Background] Apps that are transitioning to the background can ...
- java MD5 并发
Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321(R.Rives ...
- HDU 1569 方格取数(2) (最小割)
方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- Appium之uiautomator定位元素
元素定位方式有多种,Android也有自身独有的定位方式.下面就单独介绍其基于uiautomator定位元素的方法: 基本语法: driver.find_element_by_android_uiau ...
- Github注册及心得
注册Github流程: 1.搜索www.github.com 2.有两个按钮sign up(注册).sign in(登入)
- Hadoop 新建集群namenode format
在hadoop部署好了之后是不能马上应用的,还要对配置的文件系统进行格式化. 使用命令: hadoop namenode -format 注释:namenode和secondary namenode均 ...
- Neutron 是怎么实现虚拟三层网络的
Neutron 对虚拟三层网络的实现是通过其 L3 Agent (neutron-l3-agent).该 Agent 利用 Linux IP 栈.route 和 iptables 来实现内网内不同网络 ...
- MySql数据库备份的几种方式
mysqldump工具备份 备份整个数据库 $> mysqldump -u root -h host -p dbname > backdb.sql 备份数据库中的某个表 $> mys ...
- php—Smarty-缓存2(26)
一个页面中,有些数据缓存,有些数据不缓存,就是局部缓存 l $smarty->assign(“var”, “value”, true) 第三个参数:表示是否不缓存 l {$var nocac ...
- Java学习笔记XML(3)
XML简介 XML即可扩展的标记语言.因此该语言中所有的标签都是没有预先定义的,开发者可以自己随意的指定. 目前为止所有的标记的语言都属于开源的语言.由W3C组织进行一个基本的维护. 因此大家学习这些 ...