RedLock

php实现redis分布式锁

半腔热情 提交于 2020-05-08 12:29:07
前言 分布式锁一般有三种实现方式: 1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。 以下将介绍第二种方式,基于Redis实现分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了 代码实现 <?php class RedLock { private $retryDelay ; private $retryCount ; private $clockDriftFactor = 0.01 ; private $quorum ; private $servers = array (); private $instances = array (); function __construct ( array $servers , $retryDelay = 200 , $retryCount = 3 ) { $this -> servers = $servers ; $this -> retryDelay =

Redis06——Redis到底能用在什么地方(上)

元气小坏坏 提交于 2020-05-05 21:53:09
之前我们介绍了一些列关于Redis的数据结构、持久化、过期&淘汰策略、集群化等知识点,感兴趣的小伙伴可以在文章的末尾查看往期内容。今天将为大家带来Redis的应用。由于本篇文章较长,所以将拆分为两章来讲解。 除了最基本的KV缓存外,Redis还能用到以下方面。 分布式锁 在分布式应用中,经常会遇到并发问题需要处理,这个时候往往就需要用到分布式锁,而Redis很好的提供了分布式锁的处理。常用的Redis分布式锁有以下两种方式。 setnx setnx(set if not exists) :通过setnx设置key,达到获取锁的目的。处理完逻辑通过del删除key释放锁。 死锁处理 :为了避免释放锁失败,导致程序进入死锁,通常采用 给key加上过期时间 的方式来处理。 Redis2.8 开始加入了set扩展参数,支持setnx 和 expire可以同时执行,是setnx 和 expire在同一个事务中,避免了expire设置过期时间不成功的问题。 任务超时 :设置超时时间虽然能避免死锁,但是会存在因超时而使锁提前释放的可能。所以该方案不适合需要较长时间的任务。为了避免任务超时,可以采取 给key设置随机value 的方式来解决该问题。释放锁时,先匹配value是否一致,再删除key。 Redlock 除了setnx外,Redis还提供了Redlock提供Redis分布式锁。 要求

Java并发同步常用处理方法

怎甘沉沦 提交于 2020-04-24 01:51:11
synchronized jdk内置同步锁 synchronized同步互斥锁+通知等待模式 synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 1)修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 2)修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 3)修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 4)修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。 AQS同步组件 1)CountDownLatch:闭锁,通过计数来保证线程是否需要一直阻塞 2)Semaphore:控制同一时间并发线程的数目 3)CyclicBarrier:和CountDownLatch相似,都能阻阻塞线程 4)ReentrantLock 5)Condition 6)Future、FutureTask 进程间同步互斥 /** * 进程间同步(FileLock文件锁,同时开启多个进程实例,若已获得锁的实例在执行,则后面的进程实例均只能等待,当然可以使用tryLock非阻塞模式) */ private void testFileLock() { File lockFile =

项目中用到了Redis分布式锁,了解一下背后的原理

瘦欲@ 提交于 2020-04-23 08:11:13
前言 以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存。现在博主在某金融平台实习,发现Redis在生产中并不只是当作缓存这么简单。在我接触到的项目中,Redis起到了一个分布式锁的作用,具体情况是这样的: 该项目在金融平台中负责某块业务,是一个分布式系统,线上大概跑着10个左右的实例。其中有一个步骤需要用户支付一定的费用,Redis分布式锁在其中大概处于这么一个位置: 可以看到在上分布式锁之后,系统做了两个查询校验,然后向数据库中插入了一条订单记录,接着才解锁进入支付流程。 从业务的角度考虑分布式锁是好理解的,它保证了查询及插入数据整个流程的原子性,防止查询校验的时候查到脏数据,使得支付前订单信息落表的操作串行化执行。 尽管从业务上来说很好理解,但使用Redis作为分布式锁对我来说是个新知识,我打算结合项目中的代码,深挖一下这个知识点。 正文 1. 为什么要使用分布式锁 在实际项目中见过分布式锁后,就不难理解为什么要使用分布式锁了:总结来说就是分布式系统要访问共享资源,为了避免并发访问资源带来错误,我们为共享资源添加一把锁,让各个访问互斥,保证并发访问的安全性,这就是使用分布式锁的原因。 2. Redis中分布式锁的实现 redis中使用分布式锁很简单,只要使用setnx指令对某个key上锁就行: setnx lock test //上锁 del lock test

redisson集群转载

若如初见. 提交于 2020-04-09 19:17:25
转载: https://www.jianshu.com/p/f302aa345ca8 参考: https://segmentfault.com/a/1190000016976564 前几天发的一篇文章《Redlock:Redis分布式锁最牛逼的实现》,引起了一些同学的讨论,也有一些同学提出了一些疑问,这是好事儿。本文在讲解如何使用Redisson实现Redis普通分布式锁,以及Redlock算法分布式锁的几种方式的同时,也附带解答这些同学的一些疑问。 Redis几种架构 Redis发展到现在,几种常见的部署架构有: 单机模式; 主从模式; 哨兵模式; 集群模式; 我们首先基于这些架构讲解Redisson普通分布式锁实现,需要注意的是,只有充分了解普通分布式锁是如何实现的,才能更好的了解Redlock分布式锁的实现,因为 Redlock分布式锁的实现完全基于普通分布式锁 。 普通分布式锁 Redis普通分布式锁这个大家基本上只了解,本文不打算过多的介绍,上一篇文章《Redlock:Redis分布式锁最牛逼的实现》也讲的很细,并且也说到了几个重要的注意点。 所以直接show you the code,毕竟talk is cheap。 redisson版本 本次测试选择redisson 2.14.1版本。 单机模式 源码如下: // 构造redisson实现分布式锁必要的Config

玩转Redis-老板带你深入理解分布式锁

六眼飞鱼酱① 提交于 2020-04-06 12:53:14
前言 公司交给了萌新小猿一个光荣而艰巨的项目,该项目需要使用分布式锁,这可难道了小猿,只是听说过分布式锁很牛掰,其他就一概不知了,唉不懂就问呗,遂向老板请教。 老板:我们每天不都在经历分布式锁吗,我来给你回忆回忆。 小猿:好勒,瓜子板凳已备好。 本文结构 为什么要使用分布式锁 分布式锁有哪些特点 分布式锁流行算法及其优缺点 基本算法 relock算法 token算法 数据库排它锁、ZooKeeper分布式锁、Google的Chubby分布式锁 总结 1、为什么要使用分布式锁 这个问题应该拆分成以下2个问题回答。 1.1、为什么使用锁 保证在同一时刻共享资源只能被一个客户端访问; 根据锁用途分为以下两种: 共享资源只允许一个客户端操作; 共享资源允许多个客户端操作; 1.1.1、仅允许一个客户端访问 共享资源的操作不具备幂等性。 常见于 数据的修改、删除操作; 在上面的例子中, 人物事件 系统含义 经理A-N 多个线程 码农小猿-调高空调温度 非幂等共享资源 秘书的允许 获取锁 1.1.2、允许多个客户端操作 主要应用场景是:共享资源的操作具有幂等性; 如 数据的查询。 既然都具有幂等性了,为什么还需要分布式锁呢,通常是为了效率或性能,避免重复操作(尤其是消耗资源的操作)。例如我们常见的缓存方案。 在上面的例子中, 人物事件 | 系统含义 ---|--- 经理A-N | 多个线程

解决Redis分布式锁业务代码超时导致锁失效问题

試著忘記壹切 提交于 2020-03-25 00:25:06
3 月,跳不动了?>>> 1、redis分布式锁的基本实现 redis加锁命令: SETNX resource_name my_random_value PX 30000 这个命令的作用是在只有这个key不存在的时候才会设置这个key的值(NX选项的作用),超时时间设为30000毫秒(PX选项的作用) 这个key的值设为“my_random_value”。这个值必须在所有获取锁请求的客户端里保持唯一。 SETNX 值保持唯一的是为了确保安全的释放锁,避免误删其他客户端得到的锁。举个例子,一个客户端拿到了锁,被某个操作阻塞了很长时间,过了超时时间后自动释放了这个锁,然后这个客户端之后又尝试删除这个其实已经被其他客户端拿到的锁。所以单纯的用DEL指令有可能造成一个客户端删除了其他客户端的锁,通过校验这个值保证每个客户端都用一个随机字符串’签名’了,这样每个锁就只能被获得锁的客户端删除了。 既然释放锁时既需要校验这个值又需要删除锁,那么就需要保证原子性,redis支持原子地执行一个lua脚本,所以我们通过lua脚本实现原子操作。代码如下: if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end 2

分布式锁

泄露秘密 提交于 2020-03-19 19:08:55
3 月,跳不动了?>>> Java 提供了两种内置的锁的实现,一种是由 JVM 实现的 synchronized 和 JDK 提供的 Lock,当你的应用是单机或者说单进程应用时,可以使用 synchronized 或 Lock 来实现锁。当应用涉及到多机、多进程共同完成时,那么这时候就需要一个全局锁来实现多个进程之间的同步。 1. 使用场景 例如一个应用有手机 APP 端和 Web 端,如果在两个客户端同时进行一项操作时,那么就会导致这项操作重复进行。 2. 实现方式 2.1 数据库分布式锁 基于 MySQL 锁表 该实现方式完全依靠数据库唯一索引来实现。当想要获得锁时,就向数据库中插入一条记录,释放锁时就删除这条记录。如果记录具有唯一索引,就不会同时插入同一条记录。这种方式存在以下几个问题: 锁没有失效时间,解锁失败会导致死锁,其他线程无法再获得锁。 只能是非阻塞锁,插入失败直接就报错了,无法重试。 不可重入,同一线程在没有释放锁之前无法再获得锁。 采用乐观锁增加版本号 根据版本号来判断更新之前有没有其他线程更新过,如果被更新过,则获取锁失败。 2.2 Redis 分布式锁 基于 SETNX、EXPIRE 使用 SETNX(set if not exist)命令插入一个键值对时,如果 Key 已经存在,那么会返回 False,否则插入成功并返回 True

分布式总结

匆匆过客 提交于 2020-03-19 17:29:49
3 月,跳不动了?>>> CAP https://my.oschina.net/garlicts/blog/3196719 最终一致性 https://my.oschina.net/garlicts/blog/1924627 https://my.oschina.net/garlicts/blog/1924537 幂等操作 负载均衡的算法 1. 算法 1.1 轮询(Round Robin) 轮询算法把每个请求轮流发送到每个服务器上。下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。最后,(1, 3, 5) 的请求会被发送到服务器 1,(2, 4, 6) 的请求会被发送到服务器 2。 . 该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担多大的负载。下图中,服务器 2 的性能比服务器 1 差,那么服务器 2 可能无法承担多大的负载。 . 1.2 加权轮询(Weighted Round Robbin) 加权轮询是在轮询的基础上,根据服务器的性能差异,为服务器赋予一定的权值。例如下图中,服务器 1 被赋予的权值为 5,服务器 2 被赋予的权值为 1,那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1,(6) 请求会被发送到服务器 2。 . 1.3 最少连接

Redlock:Redis分布式锁最牛逼的实现

心已入冬 提交于 2019-12-20 00:34:13
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 普通实现 说道Redis分布式锁大部分人都会想到: setnx+lua ,或者知道 set key value px milliseconds nx 。后一种方式的核心实现命令如下: - 获取锁(unique_value可以是UUID等) SET resource_name unique_value NX PX 30000 - 释放锁(lua脚本中,一定要比较value,防止误解锁) if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end 这种实现方式有3大要点(也是面试概率非常高的地方): set命令要用 set key value px milliseconds nx ; value要具有唯一性; 释放锁时要验证value值,不能误解锁; 事实上这类琐最大的缺点就是它加锁时只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况: 在Redis的master节点上拿到了锁; 但是这个加锁的key还没有同步到slave节点; master故障,发生故障转移