本地锁、redis分布式锁、zk分布式锁
本地锁、redis分布式锁、zk分布式锁
https://www.cnblogs.com/yjq-code/p/dotnetlock.html
为什么要用锁?
大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持。比如:分布式锁、分布式事务。有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来实现。
基于本地缓存实现锁
为什么还要写基于本地缓存实现的锁呢,因为有些项目项目可能还是单机部署的,当随着业务量增长的时候就会变成多机部署,从单机到多机的切换过程中,我们也需要把原先业务相关的锁改成分布式锁,来保持数据的最终一致性。当然项目是使用ioc的那就更好了,切换注册时的实现类就完成了切换,非常方便。
实现思路:
用户需要用一个key和一个唯一的值(知道当前这个key的使用者是谁)来获取一个锁,获取到锁之后,执行完对应的操作然后释放掉。在释放锁的时候 4我们需要判断下当前这个锁的使用者对应的值与想要释放传递过来的值是不是相等,如果相等则可以释放,不相等则不释放。
实现代码:
public sealed class LocalLock : ILock
{
private static ConcurrentDictionary<string, object> _LockCache = new ConcurrentDictionary<string, object>();
private static ConcurrentDictionary<string, string> _LockUserCache = new ConcurrentDictionary<string, string>();
/// <summary>
/// 获取一个锁(需要自己释放)
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <returns>成功返回true</returns>
public bool LockTake(string key, string value, TimeSpan span)
{
EnsureUtil.NotNullAndNotEmpty(key, "Lockkey");
EnsureUtil.NotNullAndNotEmpty(value, "Lockvalue");
var obj = _LockCache.GetValue(key, () => { return new object(); });
if (Monitor.TryEnter(obj, span))
{
_LockUserCache[key] = value;
return true;
}
return false;
}
/// <summary>
/// 异步获取一个锁(需要自己释放)
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <returns>成功返回true</returns>
public Task<bool> LockTakeAsync(string key, string value, TimeSpan span)
{
return Task.FromResult(LockTake(key, value, span));
}
/// <summary>
/// 释放一个锁
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <returns>成功返回true</returns>
public bool LockRelease(string key, string value)
{
EnsureUtil.NotNullAndNotEmpty(key, "Lockkey");
EnsureUtil.NotNullAndNotEmpty(value, "Lockvalue");
_LockCache.TryGetValue(key, out object obj);
if (obj != null)
{
if (_LockUserCache[key] == value)
{
Monitor.Exit(obj);
return true;
}
return false;
}
return true;
}
/// <summary>
/// 异步释放一个锁
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <returns>成功返回true</returns>
public Task<bool> LockReleaseAsync(string key, string value)
{
return Task.FromResult(LockRelease(key, value));
}
/// <summary>
/// 使用锁执行一个方法
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <param name="executeAction">要执行的方法</param>
public void ExecuteWithLock(string key, string value, TimeSpan span, Action executeAction)
{
if (executeAction == null) return;
if (LockTake(key, value, span))
{
try
{
executeAction();
}
finally
{
LockRelease(key, value);
}
}
}
/// <summary>
/// 使用锁执行一个方法
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <param name="executeAction">要执行的方法</param>
/// <param name="defaultValue">默认返回</param>
/// <returns></returns>
public T ExecuteWithLock<T>(string key, string value, TimeSpan span, Func<T> executeAction, T defaultValue = default(T))
{
if (executeAction == null) return defaultValue;
if (LockTake(key, value, span))
{
try
{
return executeAction();
}
finally
{
LockRelease(key, value);
}
}
return defaultValue;
}
/// <summary>
/// 使用锁执行一个异步方法
/// </summary>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <param name="executeAction">要执行的方法</param>
public async Task ExecuteWithLockAsync(string key, string value, TimeSpan span, Func<Task> executeAction)
{
if (executeAction == null) return;
if (await LockTakeAsync(key, value, span))
{
try
{
await executeAction();
}
catch
{
throw;
}
finally
{
LockRelease(key, value);
}
}
}
/// <summary>
/// 使用锁执行一个异步方法
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="key">锁的键</param>
/// <param name="value">当前占用值</param>
/// <param name="span">耗时时间</param>
/// <param name="executeAction">要执行的方法</param>
/// <param name="defaultValue">默认返回</param>
/// <returns></returns>
public async Task<T> ExecuteWithLockAsync<T>(string key, string value, TimeSpan span, Func<Task<T>> executeAction, T defaultValue = default(T))
{
if (executeAction == null) return defaultValue;
if (await LockTakeAsync(key, value, span))
{
try
{
return await executeAction();
}
catch
{
throw;
}
finally
{
LockRelease(key, value);
}
}
return defaultValue;
}
}
class Program
{
static void Main(string[] args)
{
ILock localLock = new LocalLock();
int excuteCount = 0;
Parallel.For(0, 10000, i =>
{
localLock.ExecuteWithLock("test", Guid.NewGuid().ToString(), TimeSpan.FromSeconds(5), () =>
{
Console.WriteLine("获取锁成功");
Interlocked.Increment(ref excuteCount);
});
});
Console.WriteLine("成功次数:" + excuteCount.ToString());
Console.WriteLine("执行完成");
Console.ReadLine();
}
}
基于zk实现的分布式锁
实现思路:
在获取锁的时候在固定节点下创建一个自增的临时节点,然后获取节点列表,按照增量排序,假如当前创建的节点是排在第一个的,那就表明这个节点是得到了执行的权限,假如在它前面还有其它节点,那么就对它的上一个节点进行监听,等到上一个节点被删除了,那么该节点就得到了执行的权限了。
由于代码片段太多,待会再github自行查看实现过程。zk获取锁的速度比较慢,导致有几个可能是失败的。
基于redis的实现
实现思路:
利用redis的setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。在有效时间内如果设置成功则获取执行限权,没有那就获取权限失败。
对比下会发现redis的执行效率会比zk的快一点。
项目下载地址:https://github.com/ProjectSharing/Lock
本地锁、redis分布式锁、zk分布式锁的更多相关文章
- .net下 本地锁、redis分布式锁、zk分布式锁的实现
为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...
- Redis与Zookeeper实现分布式锁的区别
Redis实现分布式锁 1.根据lockKey区进行setnx(set not exist,如果key值为空,则正常设置,返回1,否则不会进行设置并返回0)操作,如果设置成功,表示已经获得锁,否则并没 ...
- 分布式交易系统的并发处理, 以及用Redis和Zookeeper实现分布式锁
交易系统 交易系统的数据结构 支付系统API通常需要一个“订单号”作为入参, 而实际调用API接口时使用到的往往不是真正意义的业务订单号, 而是交易订单号. 支付系统的API会使用“商户号+订单号” ...
- 【zookeeper】Apache curator的使用及zk分布式锁实现
上篇,本篇主要讲Apache开源的curator的使用,有了curator,利用Java对zookeeper的操作变得极度便捷. 其实在学之前我也有个疑虑,我为啥要学curator,撇开涨薪这些外在的 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[四]--基于Redis lua脚本机制实现分布式锁
一.redis lua介绍 Redis 提供了非常丰富的指令集,但是用户依然不满足,希望可以自定义扩充若干指令来完成一些特定领域的问题.Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[二]--基于Redisson实现分布式锁
一.redisson介绍 redisson实现了分布式和可扩展的java数据结构,支持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, L ...
- 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁
一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...
- 【分布式锁的演化】终章!手撸ZK分布式锁!
前言 这应该是分布式锁演化的最后一个章节了,相信很多小伙伴们看完这个章节之后在应对高并发的情况下,如何保证线程安全心里肯定也会有谱了.在实际的项目中也可以参考一下老猫的github上的例子,当然代码没 ...
- Redis、Zookeeper实现分布式锁——原理与实践
Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...
随机推荐
- 2016上海站EC-final总结!
2016上海站EC-final总结 本想在知乎上发起一个话题:没有半点准备实力菜得抠脚的选手突然有机会参加final是什么体验.不过感觉这样太高调了,于是..... 以上说的就是事实,毫无准备.毫无状 ...
- 对于2-sat问题的求解
一.O(n+m) 暴力不多说 二.O(m) 1.构图 2.求图的极大强连通子图 3.把每个子图收缩成单个节点,根据原图关系构造一个有向无环图 4.判断是否有解,无解则输出(退出) 5.对新图进行拓扑排 ...
- 深入理解计算机操作系统——第11章:CS模型,网络
网络编程: 11.1 客户端-服务器编程模型 (1)一个应用是由一个服务器进程和一个或多个客户端进程组成. (2)服务器管理某种资源,并且操纵这种资源来为客户端服务. CS模型: CS的基本操作是事务 ...
- Codeforces Round #296 (Div. 2) D. Clique Problem [ 贪心 ]
传送门 D. Clique Problem time limit per test 2 seconds memory limit per test 256 megabytes input standa ...
- Django学习之 - 基础ORM
ORM操作参考: http://www.cnblogs.com/wupeiqi/articles/5246483.html 1:根据类自动创建数据库表,(类创建文件:models.py) 2:根据类对 ...
- SOJ 4482 忽悠大神【最小生成树】
题目链接: http://acm.scu.edu.cn/soj/problem.action?id=4482 题意: 给定边权和点权,从一个点出发并回到该点,减少尽量多的边,每路过点和边都要把权重加到 ...
- Educational Codeforces Round 50 (Rated for Div. 2)F. Relatively Prime Powers
实际上就是求在[2,n]中,x != a^b的个数,那么实际上就是要求x=a^b的个数,然后用总数减掉就好了. 直接开方求和显然会有重复的数.容斥搞一下,但实际上是要用到莫比乌斯函数的,另外要注意减掉 ...
- AtCoder Regular Contest 091&092
091E(构造) 题意: 给出n,a,b.你需要构造出一个长度为n的n的排列,其中最长上升子序列的长度为a,最长下降子序列的长度为b. n,a,,b<=3e5 分析: 我们可以构造出这样的数列, ...
- Spring Boot使用MyBatis 3打印SQL的配置
普通Spring下的XML文件配置: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE co ...
- 关于MySQL的boolean和tinyint(1)
原文:http://blog.csdn.net/woshixuye/article/details/7089508 MySQL保存boolean值时用1代表TRUE,0代表FALSE.boolean在 ...