点击上方蓝色字关注我们~

在本文中,我们将讨论如何在.NET Core中使用Redis创建分布式锁。

当我们构建分布式系统时,我们将面临多个进程一起处理共享资源,由于其中只有一个可以一次使用共享资源,因此会导致一些意外问题!

我们可以使用分布式锁来解决这个问题。

为什么分布式锁?

首先在非集群单体应用下,我们使用锁来处理这个问题。

以下显示了一些演示锁的使用的示例代码。

public void SomeMethod()
{
//do something...   lock(obj)   {
//do ....   }
//do something...
}  

但是,这种类型的锁不能帮助我们很好地解决问题!这是一个进程内锁,只能用共享资源解决一个进程。

这也是我们需要分布式锁的主要原因!

我将使用Redis在这里创建一个简单的分布式锁。

为什么我使用Redis来完成这项工作?由于Redis的单线程特性及其执行原子操作的能力。

如何创建一个锁?

我将创建一个.NET Core Console应用程序来向您展示大概流程。

在下一步之前,我们应该运行Redis服务器!

StackExchange.Redis是.NET中最受欢迎的Reids客户端,我们将使用它来完成以下工作。

首先与Redis建立联系。

/// <summary>
/// The lazy connection.
/// </summary>
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{   ConfigurationOptions configuration = new ConfigurationOptions      {   AbortOnConnectFail = false,    ConnectTimeout = 5000,     };      configuration.EndPoints.Add("localhost", 6379);   return ConnectionMultiplexer.Connect(configuration.ToString());
});     /// <summary>
/// Gets the connection.
/// </summary>
/// <value>The connection.</value>
public static ConnectionMultiplexer Connection => lazyConnection.Value;

为了请求锁定共享资源,我们执行以下操作:

SET resource_name unique_value NX PX duration 

resource_name是应用程序的所有实例将共享的值。

unique_value必须对应用程序的每个实例都是唯一的。而他的主要目的是取消锁定(解锁)。

最后,我们还提供一个持续时间(以毫秒为单位),之后Redis将自动删除锁定。

这是C#代码中的实现。

/// <summary>
/// Acquires the lock.
/// </summary>
/// <returns><c>true</c>, if lock was acquired, <c>false</c> otherwise.</returns>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
/// <param name="expiration">Expiration.</param>
static bool AcquireLock(string key, string value, TimeSpan expiration)
{   bool flag = false;     try {   flag = Connection.GetDatabase().StringSet(key, value, expiration, When.NotExists);     }   catch (Exception ex)    {   Console.WriteLine($"Acquire lock fail...{ex.Message}");   flag = true;   }   return flag;
}

这是测试获取锁定的代码。

static void Main(string[] args)
{   string lockKey = "lock:eat";     TimeSpan expiration = TimeSpan.FromSeconds(5);
//5 person eat something...     Parallel.For(0, 5, x =>     {   string person = $"person:{x}";   bool isLocked = AcquireLock(lockKey, person, expiration);      if (isLocked)   {   Console.WriteLine($"{person} begin eat food(with lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");   }
else    {   Console.WriteLine($"{person} can not eat food due to don't get the lock.");      }   });     Console.WriteLine("end");     Console.Read();
}  

运行代码后,我们可能会得到以下结果。

只有一个人可以获得锁定!其他人等待。

虽然Redis会自动删除锁,但它也没有很好地利用共享资源!

因为当一个进程完成它的工作时,应该让其他人使用该资源,而不是无休止地等待!

所以我们也需要释放锁。

如何释放锁定?

要释放锁,我们只需删除Redis中对应的key/value!

正如我们在创建锁中所做的那样,我们需要匹配资源的唯一值,这样可以更安全地释放正确的锁。

匹配时,我们将删除锁定,这意味着解锁成功。否则,解锁不成功。

我们需要一次执行getdel命令,因此我们将使用lua脚本来执行此操作!

/// <summary>
/// Releases the lock.
/// </summary>
/// <returns><c>true</c>, if lock was released, <c>false</c> otherwise.</returns>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
static bool ReleaseLock(string key, string value)
{   string lua_script = @"   if (redis.call('GET', KEYS[1]) == ARGV[1]) then     redis.call('DEL', KEYS[1])    return true     else    return false    end     ";     try {   var res = Connection.GetDatabase().ScriptEvaluate(lua_script,      new RedisKey[] { key },     new RedisValue[] { value });    return (bool)res;   }   catch (Exception ex)    {   Console.WriteLine($"ReleaseLock lock fail...{ex.Message}");   return false;   }
}  

我们应该在进程完成后调用此方法。

当进程获得锁定并且由于某些原因而未释放锁定时,其他进程不能等到它被释放。此时,其他流程应该继续进行。

这是一个处理这个场景的示例。

Parallel.For(0, 5, x =>
{   string person = $"person:{x}";   var val = 0;   bool isLocked = AcquireLock(lockKey, person, expiration);      while (!isLocked && val <= 5000)    {   val += 250;   System.Threading.Thread.Sleep(250);     isLocked = AcquireLock(lockKey, person, expiration);   }   if (isLocked)   {   Console.WriteLine($"{person} begin eat food(with lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");   if (new Random().NextDouble() < 0.6)     {   Console.WriteLine($"{person} release lock {ReleaseLock(lockKey, person)}  {DateTimeOffset.Now.ToUnixTimeMilliseconds()}");    }
else    {   Console.WriteLine($"{person} do not release lock ....");      }   }
else    {   Console.WriteLine($"{person} begin eat food(without lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");    }
});  

运行该示例后,您将会得到以下结果。

如图所示,第3和第4在无锁情况下运行。

使用Redis创建分布式锁相关推荐

  1. Redis实现分布式锁的深入探究

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错 ...

  2. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  3. Redis——由分布式锁造成的重大事故

    作者:浪漫先生 原文:juejin.im/post/6854573212831842311 前言 基于Redis使用分布式锁在当今已经不是什么新鲜事了.本篇文章主要是基于我们实际项目中因为redis分 ...

  4. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  5. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

  6. 《Redis官方文档》用Redis构建分布式锁(悲观锁)

    2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...

  7. 基于 Redis 的分布式锁到底安全吗?

    [完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...

  8. 基于Redis实现分布式锁

    http://blog.csdn.net/ugg/article/details/41894947 背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部分的解 ...

  9. redis实现分布式锁——核心 setx+pipe watch监控key变化-事务

    如何设计一把分布式锁 我们用 redis 来实现这把分布式的锁,redis 速度快.支持事务.可持久化的特点非常适合创建分布式锁. 分布式环境中如何消除网络延迟对锁获取的影响 锁,简单来说就是存于 r ...

最新文章

  1. Android --- 单一控件覆盖其他控件的方法
  2. 自动化办公之excel教程(1):工作薄,工作表,单元格基本操作
  3. cursoradpter自动更新
  4. python 如何在一个for循环中遍历两个列表
  5. 分享:利用tcp_wrappers 保护服务安全
  6. 初识SpringSecurity
  7. Stm32:半主机模式
  8. android listview item 选中背景,Android ListView的item背景色设置和item点击无响应的解决方法...
  9. VS2008快捷键总结
  10. 北邮 形式语言与自动机
  11. ipv6有必要打开吗_路由器中的IPv6功能需不需要开启?
  12. 史上最详细金卡介绍以及金卡制作教程(附风暴数码CID转换码链接)
  13. 假设检验实验和拟合优度检验练习题
  14. 基于第二届易观算法大赛——性别年龄预测中数据的分析(娱乐向)
  15. VUE学习(一)、创建一个Vue应用。
  16. Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backs
  17. 各种品牌主板、笔记本、台式一体机的U盘启动热键一览表
  18. 追觅、戴森、石头扫地机器人对比测评,哪个性价比更高
  19. GEE哨兵二号去云不成功的原因(代码修改)
  20. 小玩意 - Chrome插件——GreenChrome(GC)失效如何解决?

热门文章

  1. Mac OS使用技巧之八:Dock栏使用技巧
  2. 亚信科技数据库AntDB通过金融分布式事务数据库标准测试
  3. Install OpenCV-Python in Ubuntu
  4. Javascript中数组去重的六种方法
  5. 一维条形码***技术(Badbarcode)
  6. [C++]VS2005(VC8) 使用 Boost
  7. RabbitMq、ActiveMq、ZeroMq、kafka之间的比较,资料汇总
  8. LVS:三种负载均衡方式与八种均衡算法
  9. 控制用户的访问之权限、角色【weber出品必属精品】
  10. 怎样自己写一个MVC框架