5种分布式锁实现的对比?

栏目: 后端 · 发布时间: 6年前

内容简介:在分布式环境下,为保证数据的一致性,需要保证同一时刻同一方法,只有一个线程在运行,即互斥

点击蓝色“ 乔志勇笔记 ”关注我哟

加个“ 星标 ”,第一时间获取推送的文章哦!

一、分布式锁的适用场景

在分布式环境下,为保证数据的一致性,需要保证同一时刻同一方法,只有一个线程在运行,即互斥

二、分布式锁的设计因素

1、互斥性

同一时刻只能有一个服务(或应用)访问资源,特殊情况下有读写锁

2、原子性

一致性要求保证加锁和解锁的行为是原子性的

3、安全性

锁只能被持有该锁的服务(或应用)释放

4、容错性

在持有锁的服务崩溃时,锁仍能得到释放避免死锁

5、可重用性

同一个客户端获得锁后可递归调用

6、公平性

看业务是否需要公平,避免饿死

7、支持阻塞和非阻塞

和 ReentrantLock 一样支持 lock 和 trylock 以及 tryLock(long timeOut)

8、高可用

获取锁和释放锁 要高可用

9、高性能

获取锁和释放锁的性能要好

10、持久性

锁按业务需要自动续约/自动延期

三、分布式锁的实现方案

1、基于数据库的实现

方案一:基于表的唯一索引

(1)创建锁记录table,用锁定的资源作为唯一索引

(2)加锁时执行一条insert插入

(3)完毕后删除 该记录

问题:

非阻塞,无容错(客户端崩溃后锁不能释放),不可重入等等

方案二:基于数据库排他锁

使用select for update 加锁 保持回话session连接 ,解锁时释放连接

问题:

回话连接性能差,还是不可重用

2、基于 redis 的实现

方案一:新的set命令 和 lua 脚本

问题:(1)非阻塞,只能通过死循环实现,通过 Redis 的订阅发布模式来实现通知的成本太高

(2)redis单点,主从切换可能出现锁丢失

方案二:实现redlock算法的redisson

Redisson是一个在Redis的基础上实现的 Java 驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上

基于redlock算法,根据lua 脚本和watch dog 机制实现了自动延期,可重入 ,还可实现读写锁、公平锁,联锁等等

问题:AP模型,无一致性算法,存在一致性问题

参考文章:

https://juejin.im/post/5bf3f15851882526a643e207

https://blog.csdn.net/turbo_zone/article/details/83422215

https://mp.weixin.qq.com/s?__biz=MzU5ODUwNzY1Nw==&mid=2247484164&idx=1&sn=210397905ef284c1d2756d1cdf73880f

https://mp.weixin.qq.com/s?__biz=MzU5ODUwNzY1Nw==&mid=2247484155&idx=1&sn=0c73f45f2f641ba0bf4399f57170ac9b&scene=21#wechat_redirect

3、 基于zookeeper的实现

基于Curator客户端实现分布式锁

  • Shared Reentrant Lock 可重入锁

  • Shared Lock 共享不可重入锁

  • Shared Reentrant Read Write Lock 可重入读写锁

  • Shared Semaphore 信号量

  • Multi Shared Lock 多锁

方案一:排他锁

创建临时有序节点 排序 后,watch比自己小1的节点等待获取锁

方案二:读写锁

  • 读锁:又称共享锁,如果前面没有写节点,可以直接上锁;当前面有写节点时,则等待距离自己最近的写节点释放( 删除 )。

  • 写锁:如果前面没有节点,可以直接上锁;如果前面有节点,则等待前一个节点释放( 删除 )

存在问题:

(1)性能上不如使用缓存实现的分布式锁,因为每次在创建锁和释放锁的过程中,都要动态创建、销毁临时节点来实现锁功能

参考文章:

利用Zookeeper实现 - 分布式锁

4、基于etcd的实现

etcd像是专门为集群环境的服务发现和注册而设计,它提供了数据TTL失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能,可以方便的跟踪并管理集群节点的状态

因为 etcd 使用 Raft 算法保持了数据的强一致性,某次操作存储到集群中的值必然是全局一致的,所以很容易实现分布式锁。锁服务有两种使用方式,一是保持独占,二是控制时序

保持独占,即所有试图获取锁的用户最终只有一个可以得到。etcd为此提供了一套实现分布式锁原子操作CAS(CompareAndSwap)的API。通过设置prevExist值,可以保证在多个节点同时创建某个目录时,只有一个成功,而该用户即可认为是获得了锁。

·控制时序,即所有试图获取锁的用户都会进入等待队列,获得锁的顺序是全局唯一的,同时决定了队列执行顺序。etcd为此也提供了一套API(自动创建有序键),对一个目录建值时指定为POST动作,这样etcd会自动在目录下生成一个当前最大的值为键,存储这个新的值(客户端编号)。同时还可以使用API按顺序列出所有当前目录下的键值。此时这些键的值就是客户端的时序,而这些键中存储的值可以是代表客户端的编号

方案:基于etcd API

尝试拿锁 + 自动续租 + 关闭清理 三个api

拿锁失败 进入等待队列

参考文章:

https://segmentfault.com/a/1190000014297365

问题:没有现成的框架,需要一定自研

5、基于consul的实现

方案:consul中锁的主要是依赖KV Store和Session相关API

(1)acquire操作只有当锁不存在持有者时才会返回true,并且set设置的Value值,同时执行操作的session会持有对该Key的锁,否则就返回false

(2)release操作则是使用指定的session来释放某个Key的锁,如果指定的session无效,那么会返回false,否则就会set设置Value值,并返回true

参考文章:http://vearne.cc/archives/39126?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

问题: 没有现成的框架,需要一定自研

为保持一致性 ,1个client释放锁之后,其它client无法立刻获得锁

四、分布式锁的总结

综合所有设计要素,发表下自我的看法:

1、如果缺乏自研能力,用redis的redisson框架最好 ,相比zk 性能比较好

2、如果拥有自研能力,基于etcd实现分布式锁是做好的,consul分布式应用不广泛

3、不建议线上业务基于数据库实现,因为基本很难用

近期文章:

Java并发编程学习体系

java8 Stream 史上最全总结

Java 网络编程"初探"

redis 知识点总结

java 核心技术学习总结 (一)

spring中"投机取巧"地限制 用户同时登陆

如果你喜欢本文

请长按二维码,关注 乔志勇笔记

5种分布式锁实现的对比?


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Apache Modules Book

The Apache Modules Book

Nick Kew / Prentice Hall PTR / 2007-02-05 / USD 54.99

"Do you learn best by example and experimentation? This book is ideal. Have your favorite editor and compiler ready-you'll encounter example code you'll want to try right away. You've picked the right......一起来看看 《The Apache Modules Book》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具