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的更多相关文章

  1. distributed lock manager (DLM)(分布式管理锁)

    A distributed lock manager (DLM) provides distributed software applications with a means to synchron ...

  2. ZooKeeper Distributed lock

    https://segmentfault.com/a/1190000016351095 http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC% ...

  3. jedisLock—redis分布式锁实现

    一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...

  4. nopCommerce 3.9 大波浪系列 之 使用Redis主从高可用缓存

    一.概述 nop支持Redis作为缓存,Redis出众的性能在企业中得到了广泛的应用.Redis支持主从复制,HA,集群. 一般来说,只有一台Redis是不可行的,原因如下: 单台Redis服务器会发 ...

  5. Redlock(redis分布式锁)原理分析

    Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...

  6. Redis实战(九)Redis的典型应用场景

    序言 数据缓存 共享Session 分布式锁 https://www.cnblogs.com/wangrudong003/p/10627539.html Redlock(redis分布式锁)原理分析 ...

  7. jedisLock—redis分布式锁实现(转)

    一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...

  8. springboot实现分布式锁(spring integration,redis)

    Springboot实现分布式锁(Spring Integration+Redis) 一.在项目的pom.xml中添加相关依赖 1)Spring Integration依赖 <dependenc ...

  9. Dapr v1.8 正式发布

    Dapr是一套开源.可移植的事件驱动型运行时,允许开发人员轻松立足云端与边缘位置运行弹性.微服务.无状态以及有状态等应用程序类型.Dapr能够确保开发人员专注于编写业务逻辑,而不必分神于解决分布式系统 ...

随机推荐

  1. Android记事本在菜单栏添加搜索按钮方法

    效果图 这个app结构和我之前将记事本开发的博客基本一致,我这里直接讲一下怎样添加 使用的开发软件为android studio 首先在res目录下新建文件夹menu,添加目录布局文件main_men ...

  2. Flink架构,源码及debug

    序 工作中用Flink做批量和流式处理有段时间了,感觉只看Flink文档是对Flink ProgramRuntime的细节描述不是很多, 程序员还是看代码最简单和有效.所以想写点东西,记录一下,如果能 ...

  3. openlayers图层加标注

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. Largest Rectangle in a Histogram POJ - 2559

    很显然是单调栈 这里记录一种新的写法,这种写法基于递推,但是相比之下比单调栈更好写 #include<cstdio> #include<map> #include<set ...

  5. Cobalt Strike配置及简单使用

    前言 CS分为客户端与服务端,服务端是一个,客户端可以有多个,非常适合团队协同作战,多个攻击者可以同时连接到一个团队服务器上,共享攻击资源与目标信息和sessions,可模拟APT做模拟对抗,进行内网 ...

  6. bugku_web_变量1(CTF)

    这道题考察php全局变量GLOBALS的用法,同样是个php审计题. 看一下代码: flag In the variable ! <?php error_reporting(0); includ ...

  7. Python标准库之subprocess模块

    运行python的时候,我们都是在创建并运行一个进程.像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序.在Python中,我们通过标准库中的subprocess ...

  8. python3练习100题——051

    题目:学习使用按位与 & . 不会的知识点,查了一下按位运算. 按位运算符是把数字看作二进制来进行计算的. 运算符 描述 实例 & 按位与运算符:参与运算的两个值,如果两个相应位都为1 ...

  9. Fiddler抓取https方法

    基本配置 菜单 -> menu -> tool -> https 勾选"捕获https连接" 勾选"捕获https流量" 勾选"检查 ...

  10. nodeJS菜鸟教程笔记

    http模块 var http = require('http'); // 引入http模块 var url = require('url'); // 引入url模块 var querystring ...