单实例的实现

从2.6.12版本开始,redis为SET命令增加了一系列选项:

  • EX seconds – 设置键key的过期时间,单位时秒
  • PX milliseconds – 设置键key的过期时间,单位时毫秒
  • NX – 只有键key不存在的时候才会设置key的值
  • XX – 只有键key存在的时候才会设置key的值

如果有2个进程(可能位于不同机器)需要竞争某个资源,可以为这个资源加锁,锁放在redis里面,这样两个进程都能访问到,例如下面的命令:

SET resource-name random-value NX EX max-lock-time

仅当key不存在时,设置一个键值对,并且设置了key的过期时间。

如果其中一个进程set成功,那么另外一个进程会set失败,只要判断set命令的返回值,就可以判断是否加锁成功。

这里resouce-name是需要加锁的资源,而random-value每个进程都可以写唯一值,而max-lock-time是锁的最大持有时间。

如何释放锁:

a客户端获得的锁(键key)已经由于过期时间到了被redis服务器删除,但是这个时候a客户端还去执行DEL命令。而b客户端已经在a设置的过期时间之后重新获取了这个同样key的锁,那么a执行DEL就会释放了b客户端加好的锁。

if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end

由于每个进程写入的value是自己生成的随机数,可以保证一个进程只能删除自己加的锁,而避免误删其它进程加的锁。

分布式锁

在分布式版本的算法里我们假设我们有N个Redis master节点,这些节点都是完全独立的,我们不用任何复制或者其他隐含的分布式协调算法。我们已经描述了如何在单节点环境下安全地获取和释放锁。因此我们理所当然地应当用这个方法在每个单节点里来获取和释放锁。在我们的例子里面我们把N设成5,这个数字是一个相对比较合理的数值,因此我们需要在不同的计算机或者虚拟机上运行5个master节点来保证他们大多数情况下都不会同时宕机。一个客户端需要做如下操作来获取锁:

1.获取当前时间(单位是毫秒)。

2.轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。比如如果锁自动释放时间是10s,那每个节点锁请求的超时时间可能是5~50ms的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。

3.客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁(在这里是3个),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。

4.如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。

5.如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,一定要尽快在获取锁成功的节点上释放锁,这样就没必要等到key超时后才能重新获取这个锁(但是如果网络分区的情况发生而且客户端无法连接到Redis节点时,会损失等待key超时这段时间的系统可用性)。

注意:当一个客户端获取锁失败时,这个客户端应该在一个随机延时后进行重试,之所以采用随机延时是为了避免不同客户端同时重试导致谁都无法拿到锁的情况出现。同样的道理客户端越快尝试在大多数Redis节点获取锁,出现多个客户端同时竞争锁和重试的时间窗口越小,可能性就越低,所以最完美的情况下,客户端应该用多路传输的方式同时向所有Redis节点发送SET命令。

参考文档:

http://ifeve.com/redis-lock/

https://github.com/SPSCommerce/redlock-py

用redis构建分布式锁的更多相关文章

  1. Redis官方文档》持久化

    原文链接 译者:Alexandar Mahone 这篇文章从技术层面描述了Redis持久化,建议所有读者阅读.如果希望更多了解Redis持久化和持久性保障,建议阅读Redis持久化揭秘. Redis ...

  2. StackExchange.Redis 官方文档(六) PipelinesMultiplexers

    原文:StackExchange.Redis 官方文档(六) PipelinesMultiplexers 流水线和复用 糟糕的时间浪费.现代的计算机以惊人的速度产生大量的数据,而且高速网络通道(通常在 ...

  3. StackExchange.Redis 官方文档(五) Keys, Values and Channels

    原文:StackExchange.Redis 官方文档(五) Keys, Values and Channels Keys, Values and Channels 在使用redis的过程中,要注意到 ...

  4. StackExchange.Redis 官方文档

    原文:StackExchange.Redis 官方文档 时隔多年的翻译终于完成了第六个,也是很重要的的官方文档,是介绍有关链接管理,管道流水线和多路复用的 官方地址在这里:官方文档 下面做个汇总: S ...

  5. 《Redis官方文档》用Redis构建分布式锁

    用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简 ...

  6. Redis官方文档资源

    官方文档: 如果要深入研究时,官方提供的文档是最权威的. 英文: https://redis.io/documentation 中文: http://www.redis.cn/documentatio ...

  7. StackExchange.Redis 官方文档(一) Basics

    基本使用方法: StackExchange.Redis的核心是 StackExchange.Redis 命名空间的 ConnectionMultiplexer 类;它隐藏了多服务器的实现细节.Conn ...

  8. StackExchange.Redis 官方文档(四) KeysScan

    KEYS, SCAN, FLUSHDB 方法在哪? 经常有人问这些问题: 好像并没有看到 Keys(...) 或者 Scan(...)方法?那我要怎么查询数据库里面存有哪些key? 或者 好像没有Fl ...

  9. StackExchange.Redis 官方文档(三) Events

    事件 ConnectionMultiplexer类型提供了很多可以用来了解表面状态下正在发生着什么的事件.这对日志是很有用的. ConfigurationChanged - ConnectionMul ...

  10. StackExchange.Redis 官方文档(二) Configuration

    配置 有多种方式可以配置redis,StackExchange.Redis提供了一个丰富的配置模型,在执行Connect (or ConnectAsync) 时被调用: var conn = Conn ...

随机推荐

  1. Mac 下安装Fiddler抓包工具

    需求 我们都知道在Mac电脑下面有一个非常好的抓包工具:Charles.但是这个只能抓代理的数据包.但是有时候想要调试本地网卡的数据库 Charles 就没办法了.就想到了在windows下面的一个F ...

  2. KeepAlive安装指南

    https://blog.csdn.net/yelllowcong/article/details/78764780

  3. Python append()方法--list

    描述 append()方法:用于向列表末尾添加新的对象. 语法 语法格式:list.append(object) 参数 object:添加到列表末尾的对象,这里的对象可以是一个元素.列表.字典或元组等 ...

  4. Mysql笔试题

    1.查询Student表中的所有记录的Sname.Ssex和Class列. SELECT Sname,Ssex,Class FROM Students; 2.查询教师所有的单位即不重复的Depart列 ...

  5. #20175201 实验一 Java开发环境的熟悉(Linux + Eclipse)

    一.实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用Eclipse 编辑.编译.运行.调试Java程序. (一)命令行下Java程序开发 1.过程 2.结果 调试代码遇到的问题: 解决 ...

  6. 学号 20175201张驰 《Java程序设计》第4周学习总结

    学号 20175201张驰 <Java程序设计>第4周学习总结 教材学习内容总结 第5章 继承:避免多个类间重复定义共同行为,用我们已经有的类,去创建新的类 任何子类都可以继承它的父类的成 ...

  7. iOS Version和Build的区别

    iOS开发中,会面对一个问题,Version和Build的区别.这两种均是版本号,但是在开发中还是有一定的区别,而且用处很大. Version 是版本号,在info.plist中对应的key是 CFB ...

  8. windows环境在本地配nginx

    本地搭建了前端项目,但奈何有时候需要https访问的需求,所以做了一个尝试在本地(windows环境)下配置nginx,最终的效果就是 搭建的时候,遇到两个问题: 第一个是如果要在本地搭建https, ...

  9. ElasticSearch 随笔

     1.如何用亚马逊S3存储一个ES服务索引.http://t.cn/R0fAJwK 2.ELK实战 - 利用Nginx日志分析API耗时.http://t.cn/R6sgQfU 3.Kibana中的地 ...

  10. Epplus DataTable一次性导出

    public void Export() { string fileName = ""; if (string.IsNullOrEmpty(fileName) == true) { ...