单实例的实现

从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. TypeScript初探

    TypeScript初探 TypeScript什么? 官方给的定义:TypeScript是一种由微软开发的自由和开源的编程语言,它是JavaScript类型的超集,可以编译成纯JavaScript,本 ...

  2. Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/maven/cli/MavenCli : Unsupported major.minor version 51.0

    原因:JDK版本不兼容.运行的Java Class文件采用高版本的JDK编译,然后在低版本的JRE环境中运行,有时会报此错误. 解决:1)升级JDK 2)调整Eclipse中Java Compiler ...

  3. [转]Jmeter + Grafana + InfluxDB 性能测试监控

    https://www.cnblogs.com/yyhh/p/5990228.html Jmeter + Grafana + InfluxDB 性能测试监控 效果不错

  4. JDK1.8 LongAdder 空间换时间: 比AtomicLong还高效的无锁实现

    我们知道,AtomicLong的实现方式是内部有个value 变量,当多线程并发自增,自减时,均通过CAS 指令从机器指令级别操作保证并发的原子性. // setup to use Unsafe.co ...

  5. NAT(Network Address Translation)

    一.概述 NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task Force, I ...

  6. uni-app第三方登陆-微信

    结合上文全局登陆校验,实现微信授权登录官方手册地址: https://uniapp.dcloud.io/api/plugins/login?id=getuserinfo 一.书写两个界面 login. ...

  7. 2019-04-20 Python之科学计算库学习总结

    一.numpy库和matplotlib库的学习 (1)numpy库介绍:科学计算包,支持N维数组运算.处理大型矩阵.成熟的广播函数库.矢量运算.线性代数.傅里叶变换.随机数生成,并可与C++/Fort ...

  8. 快速排序 之添加复合插入排序和原始序列取中值左pivot

    quicksort中,当n小于一定值时,排序效率就比直接插入排序底了,所以,此时就不要再递归下去了,直接插入排序好了:快速的原理就是因为折半递归,所以初始pivot应该有个好一点的选择,这里在原序列左 ...

  9. MYSQL.版本查看-LINUX

    MYSQL.版本查看-LINUX 方式1: 不需登录mysql,登录Linux服务后,执行如下指令: # mysql -V 注意: 那个是大写的V,如果使用小写的v,在root没有设置密码的情况下,就 ...

  10. ASP.NET gridview导出excel,防止繁体产生有乱码的方式

    //1.先引用比如 : using System; using System.Collections.Generic; using System.Linq; using System.Web; usi ...