一、分布式锁概述
在分布式系统架构下,资源共享不再是单机下的线程竞争,而是跨 JVM 过程之间的而资源共享,因而 JVM 锁不再满足业务需要,须要引入适宜分布式系统的“锁”。
二、分布式锁设计准则
- 排他性:被共享资源批准工夫内只能被一台机器上的一个线程应用,这点和 jvm 锁是一个情理。
- 防止死锁:线程获取到锁,在执行完业务之后,肯定要开释锁(包含异常情况下开释)。
- 高可用:获取和开释锁要保障高可用和性能。
- 可重入:最好是可重入锁,即以后机器的以后线程如果没有获取到锁,那么在期待肯定工夫后肯定要保障能够再被获取到。
- 偏心锁:不是硬性要求,指的是不同线程获取锁时最好保障几率一样。
三、分布式锁实现形式
1. 基于数据库级别的锁
- 乐观锁:基于 CAS(compare and swap) 原理,即在表中增加一个 version 字段,每次更新的时候以 version 作为条件,只能有一个线程更新胜利。
- 乐观锁:总是假如事件产生在最坏的状况,因而每次获取数据时都会上锁,阻塞其余线程,比方行锁、表锁、读锁、写锁。mysql 和 oracle 是通过 for update 来实现的
select fields from table for update
2. 基于 redis 的原子操作
次要通过 Redis 原子操作 SETNX 和 EXPIRE 来实现,因为 redis 是单线程机制,所以同一时刻,同一节点只容许一个线程执行某种操作,所以满足原子性。
- 结构一个与共享资源相干的 key
- 调用 SETNX 命令获取锁,并且设置过期工夫,以防死锁
- 开释锁
3. 基于 zookeeper 的互斥排他锁
zookeeper 分布式锁基于 zk 程序长期节点和 watcher 机制,举荐应用框架 curator。
- 原理:在每一个节点上面创立子节点的时候,抉择 EPHEMERAL_SEQUENTIAL 或者 PERSISTENT_SEQUENTIAL。新的子节点前面,会加上一个秩序编号。这个秩序编号,是上一个生成的秩序编号加一。
所以,能够规定编号最小的那个节点取得锁,其余节点只有监听本人前一个节点(通过订阅比本人小的节点的删除事件),并判断本人是不是最小的那个节点就能够了。
-
步骤:
- 创立一个根节点,最好是长久节点,代表分布式锁
- 须要占用锁的时候,在根节点下创立长期有序节点。
- 判断本人是否为以后节点列表中最小子节点,如果是则取得锁,否则监听前一个子节点的变更音讯。
- 解决业务流程,解决实现后,删除本人的子节点,开释锁。