Redis Distributed lock
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace RedisDemo
{
class Program
{
static void Main(string[] args)
{
TestRedisLockWithFencingToken();
Console.ReadKey();
}
public static List<int> SLEEP_OF_SECONDS = new List<int> { 20, 0, 0, 10, 10 };
public static void TestRedisLockWithFencingToken()
{
var tasks = new List<Task>();
var mockService = new MockService();
Enumerable.Range(1, 3).ToList().ForEach(it =>
{
var task = Task.Run(() =>
{
var taskId = $"task_{it}";
var lockHelper = new RedisLockHelper();
var lockKey = "article:1";
try
{
Console.WriteLine($"-> {taskId} begin acquire redis lock.");
var result = lockHelper.GetLock(lockKey, TimeSpan.FromSeconds(10));
if (result.Success)
{
var taskInfo = new TaskInfo { TaskId = taskId, FencingToken = result.FencingToken ?? 0 };
Console.WriteLine($"-> {taskId} acquire lock success {taskInfo}.");
var sleepOfSeconds = SLEEP_OF_SECONDS[it - 1];
Thread.Sleep(sleepOfSeconds * 1000);
mockService.Save(taskInfo);
Console.WriteLine($"{taskInfo} Done");
}
}
catch (Exception ex)
{
Console.WriteLine($"{taskId} {ex.Message}");
}
finally
{
lockHelper.ReleaseLock("article:1");
}
});
tasks.Add(task);
});
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
}
public class TaskInfo
{
public long FencingToken { get; set; }
public string TaskId { get; set; }
public override string ToString()
{
return $"TaskId: {TaskId} - FencingToken: {FencingToken}";
}
}
public class MockService
{
private IConnectionMultiplexer connection;
private String fencingTokenKey = "redis_fencingToken";
public MockService()
{
this.Initialize();
}
private void Initialize()
{
connection = ConnectionMultiplexer.Connect("localhost");
}
public void Close()
{
if (connection != null)
{
connection.Close();
}
}
public void Save(TaskInfo taskInfo)
{
Console.WriteLine($"MockService#Save: {taskInfo}");
var fencingToken = taskInfo.FencingToken;
var serverFencingToken = connection.GetDatabase().StringGet(fencingTokenKey);
Console.WriteLine($"MockService#Save: {taskInfo} - Server Fencing Token {serverFencingToken}");
if (serverFencingToken.HasValue)
{
if (fencingToken == (long)serverFencingToken)
{
Console.WriteLine($"MockService#Save: {taskInfo} Save Success.");
}
else
{
Console.WriteLine($"MockService#Save: {taskInfo} Save Failure, Fencingtoken not equal server token.");
}
}
else
{
Console.WriteLine($"{taskInfo} Save error");
}
}
}
public class RedisLockResult
{
public bool Success { get; set; }
public long? FencingToken { get; set; }
}
public class RedisLockHelper : IDisposable
{
private IConnectionMultiplexer connection;
private String value;
private String fencingTokenKey = "redis_fencingToken";
public RedisLockHelper()
{
value = Guid.NewGuid().ToString();
this.Initialize();
}
public RedisLockResult GetLock(String key, TimeSpan expiry)
{
var db = connection.GetDatabase();
var lockSuccess = db.StringSet(key, value, expiry, When.NotExists, CommandFlags.None);
var start = DateTime.Now;
while (!lockSuccess)
{
Thread.Sleep(50);
lockSuccess = db.StringSet(key, value, expiry, When.NotExists, CommandFlags.None);
start = start.AddMilliseconds(50);
if (DateTime.Now.Subtract(start).TotalSeconds > 20)
{
throw new InvalidOperationException($"can not acquire distributed lock");
}
}
var result = new RedisLockResult()
{
Success = lockSuccess
};
if (lockSuccess)
{
var fencingToken = db.StringIncrement(fencingTokenKey, 1, CommandFlags.None);
result.FencingToken = fencingToken;
}
return result;
}
public void ReleaseLock(RedisKey key)
{
var lua = @"if redis.call('get', @key) == @value then
return redis.call('del', @key)
else
return 0
end";
var db = connection.GetDatabase();
var prepare = LuaScript.Prepare(lua);
var result = db.ScriptEvaluate(prepare, new { key = key, value = value });
}
private void Initialize()
{
connection = ConnectionMultiplexer.Connect("localhost");
}
public void Dispose()
{
if (connection != null)
{
connection.Dispose();
}
}
}
}
Redis Distributed lock的更多相关文章
- distributed lock manager (DLM)(分布式管理锁)
A distributed lock manager (DLM) provides distributed software applications with a means to synchron ...
- ZooKeeper Distributed lock
https://segmentfault.com/a/1190000016351095 http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC% ...
- jedisLock—redis分布式锁实现
一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...
- nopCommerce 3.9 大波浪系列 之 使用Redis主从高可用缓存
一.概述 nop支持Redis作为缓存,Redis出众的性能在企业中得到了广泛的应用.Redis支持主从复制,HA,集群. 一般来说,只有一台Redis是不可行的,原因如下: 单台Redis服务器会发 ...
- Redlock(redis分布式锁)原理分析
Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...
- Redis实战(九)Redis的典型应用场景
序言 数据缓存 共享Session 分布式锁 https://www.cnblogs.com/wangrudong003/p/10627539.html Redlock(redis分布式锁)原理分析 ...
- jedisLock—redis分布式锁实现(转)
一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...
- springboot实现分布式锁(spring integration,redis)
Springboot实现分布式锁(Spring Integration+Redis) 一.在项目的pom.xml中添加相关依赖 1)Spring Integration依赖 <dependenc ...
- Dapr v1.8 正式发布
Dapr是一套开源.可移植的事件驱动型运行时,允许开发人员轻松立足云端与边缘位置运行弹性.微服务.无状态以及有状态等应用程序类型.Dapr能够确保开发人员专注于编写业务逻辑,而不必分神于解决分布式系统 ...
随机推荐
- mnist手写数字问题初体验
上一篇我们提到了回归问题中的梯度下降算法,而且我们知道线性模型只能解决简单的线性回归问题,对于高维图片,线性模型不能完成这样复杂的分类任务.那么是不是线性模型在离散值预测或图像分类问题中就没有用武之地 ...
- gulp常用插件之gulp-htmlmin使用
更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-htmlmin这是一款HTML文件压缩插件. 更多使用文档请点击访问gulp-htmlmin工具官网. 安装 一键安装不多解释 npm ...
- SurfaceView 与view区别详解
SurfaceView 与view区别详解 https://blog.csdn.net/u011339364/article/details/83347109 2018年10月24日 17:20:08 ...
- html5的页面在IOS中,按钮 变成圆角怎么办?
在button的css 中添加: -webkit-appearance: none; border: none; border-radius: 0; ok 的啦 文章来源:刘俊 ...
- C# 引入Sqlite 未能加载文件或程序集“System.Data.SQLite
个人博客 地址:https://www.wenhaofan.com/article/20190501224046 问题 在Visual Studio 中 使用NuGet 通过 install-pack ...
- JVM内存模型以及HotSpot的GC策略
概述 想要进一步掌握Java语言,必须要深入了解一下Java程序的运行环境.本文会对JVM的内存模型.Java内存自动管理机制.以及Oracle官方虚拟机HotSpot在GC方面的实现策略进行大概的梳 ...
- (一)Python模块化编程简介
1 引言 众所周知,模块化编程具备很多优点,尤其在复杂项目上体现更为明显.Python模块化编程有助于开发者统筹兼顾和分工协作,并提升代码灵活性和可维护性,是编程开发者不可或缺的一项重要工具. 2 P ...
- HashMap源码刨析(面试必看)
目录 1.Hash的计算规则? 2.HashMap是怎么形成环形链表的(即为什么不是线程安全)?(1.7中的问题) 3.JDK1.7和1.8的HashMap不同点? 4.HashMap和HashTab ...
- 0004 工程配置settings.py
两个目录的区别: 工程目录是指包含manage.py文件的目录 配置目录是批包含settings.py文件的目录 在配置目录中找到并打工settings.py文件,做以下配置: 01 DEBUG DE ...
- unrecognized import path "golang.org/x/*"的解决办法
由于国内网络原因,因此访问https://golang.org/网站会被限制.所以在go get下载其他第三方包的时候,如果这个第三方包又引用了https://golang.org/x/下的包,通常会 ...