找项目网找项目网  2023-05-18 22:11 找项目网 隐藏边栏
导语: 一、线程锁和分布式锁常见的分布式锁实现:DistributedLock开源项目中有多种实现方式,我们主要讨论Redis中的分布式锁实现。二、Redis分布式锁的实现原理参数可以实现「key不存在才插入」,所以可以用它来实现分布式锁:库实现分布式锁和续租机制的示例代码:Redis类库,对Acquire的具体实现,该方法是尝试获取Redis分布式锁实例。

↓推荐关注↓

一、线程锁和分布式锁

线程锁通常在单个进程中使用,以防止多个线程同时访问共享资源。

在我们.NET中常见的线程锁有:

更多的线程同步锁,可以看这篇文章:

分布式锁是一种用于协调多个进程/节点之间的并发访问的机制,某个资源在同一时刻只能被一个应用所使用,可以通过一些共享的外部存储系统来实现跨进程的同步和互斥

常见的分布式锁实现:

DistributedLock开源项目中有多种实现方式,我们主要讨论Redis中的分布式锁实现。

二、Redis分布式锁的实现原理

基础实现

Redis 本身可以被多个客户端共享访问,正好就是一个共享存储系统,可以用来保存分布式锁,而且 Redis 的读写性能高,可以应对高并发的锁操作场景。

Redis 的 SET 命令有个 NX 参数可以实现「key不存在才插入」,所以可以用它来实现分布式锁:

释放锁的时候需要删除key,或者使用lua脚本来保证原子性。

续租机制

基于上文中的实现方式,我们在设置key过期时间时,不能准确的描述业务处理时间。为了防止因为业务处理时间较长导致锁过期而提前释放锁,通过不断更新锁的过期时间来保持锁的有效性,避免了因锁过期而导致的并发问题。

关于这个问题,目前常见的解决方法有两种:

1、实现自动续租机制:额外起一个线程,定期检查线程是否还持有锁,如果有则延长过期时间。DistributedLock里面就实现了这个方案,使用“看门狗”定期检查(每1/3的锁时间检查1次),如果线程还持有锁,则刷新过期时间。

2、实现快速失败机制:当我们解锁时发现锁已经被其他线程获取了,说明此时我们执行的操作已经是“不安全”的了,此时需要进行回滚,并返回失败。

以下是使用StackExchange.Redis 库实现分布式锁和续租机制的示例代码:

RedLock

Redlock 是一种分布式锁实现方案,它的设计目标是解决 Redis 集群模式下的分布式锁并发控制问题。

它是基于多个 Redis 节点的分布式锁,即使有节点发生了故障,锁变量仍然是存在的setnx分布式锁原理,客户端还是可以完成锁操作

Redlock 算法加锁三个过程:

客户端获取当前时间(t1)。

客户端按顺序依次向 N 个 Redis 节点(官方推荐是至少部署 5 个 Redis 节点)执行加锁操作:

一旦客户端从超过半数(大于等于 N/2+1)的 Redis 节点上成功获取到了锁,就再次获取当前时间(t2),然后计算计算整个加锁过程的总耗时(t2-t1)。如果 t2-t1 < 锁的过期时间,此时,认为客户端加锁成功,否则认为加锁失败。

加锁成功后,客户端需要重新计算这把锁的有效时间,计算的结果是「锁最初设置的过期时间」减去「客户端从大多数节点获取锁的总耗时(t2-t1)」。如果计算的结果已经来不及完成共享数据的操作了,我们可以释放锁,以免出现还没完成数据操作,锁就过期了的情况。

加锁失败后,客户端向所有 Redis 节点发起释放锁的操作,释放锁的操作和在单节点上释放锁的操作一样,只要执行释放锁的 Lua 脚本就可以了。

三、DistributedLock开源项目简介

项目介绍

DistributedLock 是一个 .NET 库,它基于各种底层技术提供强大且易于使用的分布式互斥体、读写器锁和信号量。

DistributedLock 包含基于各种技术的实现;可以单独安装实现包,也可以只安装 DistributedLock NuGet 包,这是一个“元”包,其中包含所有实现作为依赖项。请注意,每个包都根据 SemVer 独立进行版本控制。

基础使用

以下两种方法,都是基于RedLock来实现的,在单机上,使用了续租机制,更多细节可以自己观看源码,下文中会简单介绍源码。

Acquire 方法返回一个代表持有锁的“句柄”对象。当句柄被处理时,锁被释放:

虽然 Acquire 将阻塞直到锁可用,但还有一个 TryAcquire 变体,如果无法获取锁(由于在别处持有),则返回 null :

支持异步和依赖注入,依赖注入:

四、浅析DistributedLock的Redis实现源码地址

目录解析

zookeeper下的分布式锁_用缓存实现分布式锁_setnx分布式锁原理

Redis的实现过程

以下代码对源码,进行了删减和修改,只想简单的讲述一下实现过程。

定义一个工厂接口,返回IDistributedLock,在依赖注入场景中,使用这个工厂接口可能会更加方便

IDistributedLock:定义了控制并发访问的基本操作。该接口支持同步和异步方式获取锁,并提供超时和取消功能,以适应各种情况

DistributedLock.Redis类库,对Acquire的具体实现,该方法是尝试获取Redis分布式锁实例。

根据当前线程是否在同步上下文,对单库和多库实现进行区分和实现

单库获取Redis分布式锁setnx分布式锁原理,就是通过set nx 设置值,返回bool,失败就释放资源,成功检查是否超时。不超时就返回任务字典

多库中是否获取到分布式锁

截止到目前,我们就知道如何获取和设置分布式锁了。接下来我们就看下是如何实现续租机制的。就是LeaseMonitor这个对象。

RunMonitoringLoopIterationAsync 里边最终调用了续时的lua脚本

用缓存实现分布式锁_setnx分布式锁原理_zookeeper下的分布式锁

你们在公司中,都是如何实现分布式锁的呢?可以在评论区留下您宝贵的建议。

———END———
限 时 特 惠:本站每日持续更新海量各大内部创业教程,一年会员只需128元,全站资源免费下载点击查看详情
站 长 微 信:jiumai99

1.站长不是项目作者,不对项目解答及盈亏负责。
2.本站所有项目来源于投稿或购买自其他第三方,若本站侵犯了您的权益请 联系站长 进行删除处理。
找项目网
找项目网 关注:0    粉丝:0
这个人很懒,什么都没写
扫一扫二维码分享
×
Dragon