@郑昀汇总
关键词:
并发控制
防止并发
英文关键词:
Distributed Lock
Distributed Lock Manager
电商目的:
保证整个(分布式)系统内对一个重要事物(订单,账户等)的有效操作线程 ,同一时间内有且只有一个。比如交易中心有N台服务器,订单中心有M台服务器,如何保证一个订单的同一笔支付处理,一个账户的同一笔充值操作是原子性的。
基于哪些服务实现分布式锁?
- memcache
- ZooKeeper
- Redis
- Hazelcast
- google Chubby
基于memcache的分布式锁
memcache的所有命令都是原子性的(internally atomic),所以利用它的add命令即可。
郑昀列出一段简单但埋下了问题的伪码:
if (cache.add("lock:{orderid}", currenttimestamp, expiredtime)) {// 已获得锁,继续try{do something}catch{...}cache.delete("lock.{orderid}")} else {// 或等待锁超时,或重试,或返回}
上面代码所暴露的常见性问题
1)如持有锁的线程异常退出或宕机,锁并没有释放;
2)设置了key的expire,那么如果有新线程在key过期后拿到了新的锁,原来超时的线程回来时,如果不经判断会误认为那是它持有的锁,会误删锁。
1)强制释放
在键值上做文章,存入的是 current UNIX time+lock timeout+1 ,这样其他线程可以通过锁的键值对应的时间戳来判断这种情况是否发生了,如果当前的时间已经大于lock.{orderid}的键值,说明该锁已失效,可以被重新使用。
2)释放自己持有的锁时,先检查是否已超时
持有锁的线程在解锁之前应该再检查一次自己的锁是否已经超时,再去做DELETE操作,因为可能客户端因为某个耗时的操作而挂起,操作完的时候锁因为超时已经被别人获得,这时就不必解锁了。
上面的办法会引入新问题:
如果多个线程检测到锁超时,都尝试去释放锁,那么就会出现竞态条件(race condition)。
场景是,
- C0操作超时了,但它还持有着锁,C1和C2读取lock.{orderid}检查时间戳,先后发现超时了。
- C1 发送delete lock.{orderid},
- C1 发送set lock.{orderid} 且成功。
- C2 发送delete lock.{orderid},
- C2 发送set lock.{orderid} 且成功。
这样,C1和C2都认为自己拿到了锁。
如果比较在意这种竞态条件,那么推荐使用基于zookeeper或redis的解决方案。
基于ZooKeeper的分布式锁
这主要得益于ZooKeeper为我们保证了数据的强一致性,即用户只要完全相信每时每刻,zk集群中任意节点(一个zk server)上的相同znode的数据一定是相同的。锁服务可以分为两类,一个是保持独占,另一个是控制时序。
所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁,通过 create znode的方式来实现。所有客户端都去创建 /distributed_lock 节点,最终成功创建的那个客户端也就拥有了这把锁。
控制时序,就是所有试图获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序。做法和上面基本类似,只是这里 /distributed_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指 定)。zk的父节点(/distributed_lock)维持一份sequence,保证子节点创建的时序性,从而形成了每个客户端的全局时序。
ZooKeeper 里实现分布式锁的基本逻辑:
- 客户端调用create()方法创建名为“_locknode_/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。
- 客户端调用getChildren(“_locknode_”)方法来获取所有已经创建的子节点,同时在这个节点上注册上子节点变更通知的Watcher。
- 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,那么就认为这个客户端获得了锁。
- 如果在步骤3中发现自己并非是所有子节点中最小的,说明自己还没有获取到锁,就开始等待,直到下次子节点变更通知的时候,再进行子节点的获取,判断是否获取锁。
释放锁的过程相对比较简单,就是删除自己创建的那个子节点即可。
基于Redis的分布式锁
接着前面的竞态条件说,同样的场景下,使用Redis的SETNX(即SET if Not eXists,类似于memcache的add)和GETSET(先写新值,返回旧值,原子性操作,可以用于分辨是不是首次操作)命令便可迎刃而解:
- C3发送SETNX lock.{orderid} 想要获得锁,由于C0还持有锁,所以Redis返回给C3一个0,
- C3发送GET lock.{orderid} 以检查锁是否超时了,如果没超时,则等待或重试。
- 反之,如果已超时,C3通过下面的操作来尝试获得锁:
GETSET lock.{orderid} <current Unix time + lock timeout + 1> - 通过GETSET,C3拿到的时间戳如果仍然是超时的,那就说明,C3如愿以偿拿到锁了。
- 如果在C3之前,有个叫C4的客户端比C3快一步执行了上面的操作,那么C3拿到的时间戳是个未超时的值,这时,C3没有如期获得锁,需要再次等待或重试。留意一下,尽管C3没拿到锁,但它改写了C4设置的锁的超时值,不过这一点非常微小的误差带来的影响可以忽略不计。
jeffkit的伪码参考:
-
# get lock
-
lock = 0
-
while lock != 1:
-
timestamp = current Unix time + lock timeout + 1
-
lock = SETNX lock.orderid timestamp
-
if lock == 1 or (now() > (GET lock.orderid) and now() > (GETSET lock.orderid timestamp)):
-
break
-
else:
-
sleep(10ms)
-
-
do_your_job()
-
-
# release lock
-
if now() < GET lock.orderid:
-
DEL lock.orderid
参考资源:
1,jeffkit,用Redis实现分布式锁,基于redis;
2,rdc.taobao,ZooKeeper典型使用场景一览;
3,Ilya Sterin,Distributed locking made easy,基于zookeeper;
4,迟炯,解读Google分布式锁服务;
5,淘宝RDC,2012,zookeeper分布式锁避免羊群效应(Herd Effect);
相关推荐
常见的分布式锁实现包括基于Zookeeper、Redis或数据库的分布式锁,它们通常采用乐观锁或悲观锁策略,确保在多个节点间安全地进行资源访问。 分布式事务则涉及多个节点之间的数据一致性保证。本地事务在单一资源管理...
分布式锁是一种在分布式系统中实现资源互斥访问的机制,主要应用于解决多节点并发操作同一资源的问题,确保数据的一致性和完整性。在标题和描述中提到的场景,如APP快速连续点击导致的重复数据问题、用户下单时的...
从Paxos到Zookeeper:分布式一致性原理与实践,适合分布式系统各阶段学习,并对分布式架构有深入的理解与提高
MATLAB代码:分布式电源接入对配电网影响分析 关键词:分布式电源 配电网 评估 参考文档:《自写文档,联系我看》参考选址定容模型部分; 仿真平台:MATLAB 主要内容:代码主要做的是分布式电源接入场景下对配电网...
分布式锁是一种在分布式系统中实现资源互斥访问的机制,主要应用于多服务共享资源的场景。在单机环境中,我们通常使用线程锁(如Java的`synchronized`关键字或`Lock`接口)来保证线程安全,但在分布式环境里,由于...
分布式锁的应用场景非常广泛,例如在电商平台中,分布式锁可以用来解决抢单问题,在金融系统中,分布式锁可以用来解决资金交易问题。 知识点七:分布式锁的优缺点 分布式锁的优点是可以解决分布式系统中的锁问题,...
分布式锁是解决分布式系统中并发控制的重要工具,如Zookeeper提供的分布式锁。一致性哈希则用于解决分布式环境下的动态扩容和缩容问题,保持数据分布的稳定性。 9. 分布式调度框架 如Airflow、Luigi等,它们用于...
在现代的电子商务环境中,分布式缓存管理技术是支撑系统高效运行的关键因素。分布式缓存能够在多台服务器上存储数据的副本,从而提高数据访问的性能和系统的可用性。在面对高并发场景时,分布式缓存能够显著降低...
分布式锁是一种在分布式系统中实现锁机制的技术,用于在多节点之间协调访问共享资源,确保在高并发环境下数据的一致性和完整性。本压缩包“zk:redis分布式锁.zip”提供了基于Zookeeper(zk)和Redis两种分布式锁实现...
MATLAB代码:分布式最优潮流 关键词:网络划分;分布式光伏;集群电压控制;分布式优化;有功缩减 参考文档:《含分布式光伏的配电网集群划分和集群电压协调控制》 仿真平台:MATLAB 主要内容:本文以全局电压的低...
分布式存储系统:HBase:分布式存储系统概论.docx
分布式存储系统:HDFS:分布式存储系统概论.docx
基于consul的分布式锁工具,包含:互斥锁、信号量等工具 基于Consul的分布式锁工具 在构建分布式系统的时候,我们经常需要控制对共享资源的访问。这个时候我们就涉及到分布式锁(也称为全局锁)的实现,本项目将...
在分析开源大数据引擎时,分布式Greenplum数据库内核是一个值得深入探讨的主题。Greenplum作为一个大规模并行处理(MPP)架构的开源数据库系统,特别适用于大数据存储、计算、分析和挖掘的应用场景。在本篇文章中,...
分布式存储系统:Cassandra:分布式存储系统概论:Cassandra的架构与特性.docx
在IT行业中,尤其是在大型分布式系统的设计与开发中,分布式锁是一种关键的同步机制。本篇文章将深入探讨如何在C#.NET环境下利用Redis实现分布式锁,以及相关的核心知识点。 首先,让我们理解什么是分布式锁。...
分布式存储系统:Google Cloud Storage:分布式存储系统概论.docx
zk分布式锁1 在分布式系统中,分布式锁是必不可少的组件之一。分布式锁可以确保在分布式环境中,多个节点之间的并发访问被正确地处理。ZooKeeper是一个广泛使用的分布式锁实现方案,本文将对ZooKeeper分布式锁进行...
架构图:分布式数据仓库架构图