c# 基于redis分布式锁
在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。 而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记可以理解为锁。
不同地方实现锁的方式也不一样,只要能满足所有线程都能看得到标记即可。如 Java 中 synchronize 是在对象头设置标记,Lock 接口的实现类基本上都只是某一个 volitile 修饰的 int 型变量其保证每个线程都能拥有对该 int 的可见性和原子修改,linux 内核中也是利用互斥量或信号量等内存数据做标记。 除了利用内存数据做锁其实任何互斥的都能做锁(只考虑互斥情况),如流水表中流水号与时间结合做幂等校验可以看作是一个不会释放的锁,或者使用某个文件是否存在作为锁等。只需要满足在对标记进行修改能保证原子性和内存可见性即可。 1 什么是分布式? 分布式的 CAP 理论告诉我们: 任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。 目前很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于 CAP理论,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证最终一致性。 分布式场景 此处主要指集群模式下,多个相同服务同时开启. 在许多的场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。很多时候我们需要保证一个方法在同一时间内只能被同一个线程执行。在单机环境中,通过 Java 提供的并发 API 我们可以解决,但是在分布式环境下,就没有那么简单啦。
● 分布式与单机情况下最大的不同在于其不是多线程而是多进程。
● 多线程由于可以共享堆内存,因此可以简单的采取内存作为标记存储位置。而进程之间甚至可能都不在同一台物理机上,因此需要将标记存储在一个所有进程都能看到的地方。
什么是分布式锁?
● 当在分布式模型下,数据只有一份(或有限制),此时需要利用锁的技术控制某一时刻修改数据的进程数。
● 与单机模式下的锁不仅需要保证进程可见,还需要考虑进程与锁之间的网络问题。(我觉得分布式情况下之所以问题变得复杂,主要就是需要考虑到网络的延时和不可靠。。。一个大坑)
● 分布式锁还是可以将标记存在内存,只是该内存不是某个进程分配的内存而是公共内存如 Redis、Memcache。至于利用数据库、文件等做锁与单机的实现是一样的,只要保证标记能互斥就行。 2 我们需要怎样的分布式锁? 可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。 这把锁要是一把可重入锁(避免死锁) 这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条) 这把锁最好是一把公平锁(根据业务需求考虑要不要这条) 有高可用的获取锁和释放锁功能 获取锁和释放锁的性能要好
public interface IDistributedLock
{
ILockResult Lock(string resourceKey);
ILockResult Lock(string resourceKey, TimeSpan expiryTime);
ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime);
ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken);
Task<ILockResult> LockAsync(string resourceKey);
Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime);
Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime);
Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken);
} public interface ILockResult : IDisposable
{
string LockId { get; }
bool IsAcquired { get; }
int ExtendCount { get; }
}
class EndPoint:RedLock.RedisLockEndPoint
{
private readonly string _connectionString;
public EndPoint(string connectionString)
{
_connectionString = connectionString;
//139.196.40.252,password=xstudio,defaultDatabase=9
var connection = connectionString.Split(',');
var dict = new Dictionary<string, string>();
foreach (var item in connection)
{
var keypar = item.Split('=');
if (keypar.Length>)
{
dict[keypar[]] = keypar[];
}
}
this.EndPoint = new System.Net.DnsEndPoint(connection[], );
if (dict.TryGetValue("password", out string password))
{
this.Password = password;
}
if (dict.TryGetValue("defaultDatabase", out string defaultDatabase) && int.TryParse(defaultDatabase,out int database))
{
RedisDatabase = database;
}
}
}
[Export(typeof(IDistributedLock))]
class InnerLock : IDistributedLock
{
private static Lazy<RedLock.RedisLockFactory> _factory; static InnerLock()
{
_factory = new Lazy<RedisLockFactory>(() => new RedisLockFactory(new EndPoint(ConfigurationManager.AppSettings["Redis"])), System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
}
public ILockResult Lock(string resourceKey)
{
return new LockResult(_factory.Value.Create(resourceKey, TimeSpan.FromDays()));
} public ILockResult Lock(string resourceKey, TimeSpan expiryTime)
{
return new LockResult(_factory.Value.Create(resourceKey, expiryTime));
} public ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime)
{
return new LockResult(_factory.Value.Create(resourceKey, expiryTime, waitTime, retryTime));
} public ILockResult Lock(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken)
{
return new LockResult(_factory.Value.Create(resourceKey, expiryTime, waitTime, retryTime, cancellationToken));
} public async Task<ILockResult> LockAsync(string resourceKey)
{
var result = await _factory.Value.CreateAsync(resourceKey, TimeSpan.FromDays());
return new LockResult(result);
} public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime)
{
var result = await _factory.Value.CreateAsync(resourceKey, expiryTime);
return new LockResult(result);
} public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime)
{
var result = await _factory.Value.CreateAsync(resourceKey, expiryTime, waitTime, retryTime);
return new LockResult(result);
} public async Task<ILockResult> LockAsync(string resourceKey, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken)
{
var result = await _factory.Value.CreateAsync(resourceKey, expiryTime, waitTime, retryTime, cancellationToken);
return new LockResult(result);
}
} class LockResult : ILockResult
{
private IRedisLock _lock;
public LockResult(IRedisLock redisLock)
{
_lock = redisLock;
} public string LockId => _lock.LockId; public bool IsAcquired => _lock.IsAcquired; public int ExtendCount => _lock.ExtendCount; public void Dispose()
{
_lock.Dispose();
}
}
https://github.com/samcook/RedLock.net
https://github.com/StackExchange/StackExchange.Redis/
c# 基于redis分布式锁的更多相关文章
- RedLock.Net - 基于Redis分布式锁的开源实现
工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...
- 基于Redis分布式锁(获取锁及解锁)
目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...
- 基于Redis分布式锁的正确打开方式
分布式锁是在分布式环境下(多个JVM进程)控制多个客户端对某一资源的同步访问的一种实现,与之相对应的是线程锁,线程锁控制的是同一个JVM进程内多个线程之间的同步.分布式锁的一般实现方法是在应用服务器之 ...
- 基于 Redis 分布式锁
1.主流分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis 等) 基于 Zookeeper 2.根据实现方式分类 : 类 CAS 自旋式分布式锁:询问的方式,类似 java 并发编程中的线 ...
- 基于redis分布式锁实现“秒杀”
转载:http://blog.5ibc.net/p/28883.html 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓“秒杀”的基本思路. 业务场 ...
- 基于redis分布式锁实现“秒杀”(转载)
转载:http://blog.csdn.net/u010359884/article/details/50310387 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的de ...
- 分布式-技术专区-Redis分布式锁实现-第一步
承接前面一篇Redis分布式锁的原理介绍 https://www.cnblogs.com/liboware/p/11921759.html 我们针对于实现方案进行接下来上篇进行重新的规划和定义以及完善 ...
- 基于SpringBoot AOP面向切面编程实现Redis分布式锁
基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...
- Redis分布式锁,基于StringRedisTemplate和基于Lettuce实现setNx
使用redis分布式锁,来确保多个服务对共享数据操作的唯一性一般来说有StringRedisTemplate和RedisTemplate两种redis操作模板. 根据key-value的类型决定使用哪 ...
随机推荐
- HDU 3639 Hawk-and-Chicken (强连通缩点+DFS)
<题目链接> 题目大意: 有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两 ...
- springcloud(六):配置中心git示例
随着线上项目变的日益庞大,每个项目都散落着各种配置文件,如果采用分布式的开发模式,需要的配置文件随着服务增加而不断增多.某一个基础服务信息变更,都会引起一系列的更新和重启,运维苦不堪言也容易出错.配置 ...
- Java数组实现循环队列的两种方法
用java实现循环队列的方法: 1.添加一个属性size用来记录眼下的元素个数. 目的是当head=rear的时候.通过size=0还是size=数组长度.来区分队列为空,或者队列已满. 2.数组中仅 ...
- Mybatis之占位符与拼接符
1.占位符 1.1 含义: 在持久化框架中,为了将约束条件中的可变参数从sql中分离出来,在原有的参数位置使用特殊的标记来标记该位置,后期通过代码给sql传递参数(即实现sql与代码分离开).这个特 ...
- Xamarin Essentials教程磁力计Magnetometer
Xamarin Essentials教程磁力计Magnetometer 磁力计也叫地磁.磁感器,可用于测试磁场强度和方向.在手持设备中,通过磁力计可以计算设备的左右.前后倾斜角度,广泛应用于手机各 ...
- angular笔记_8(事件)
ng-click 鼠标点击 ng-dblclick 鼠标双击 ng-change value改变 ng-blur ...
- JavaScript基础笔记(四) JS式面向对象
JS式面向对象 一.理解对象 一)属性类型 ECMA-262 第 5 版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征. ECMA-262 定义这些特性是为 ...
- SpringMVC框架简介
1.简介 SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 01.Spring mvc的优缺点 M ...
- BZOJ5057 : 区间k小值5
整体二分,按时间顺序依次考虑对于权值落在$[l,r]$内的所有操作. 对于每个修改操作,若权值范围完全包含了$[l,r]$,那么在更深层的分治中它都完全包含它,对每个询问的贡献是定值,因此在当前层将贡 ...
- 前端利器Emmet
前端利器Emmet Emmet可以通过缩写生成代码片段,可以提升前端开发的效率.使用方法就是输入HTML或者CSS的缩写,然后按tab键自动生成.原文在这里 后代 > <!-- nav&g ...