• 在.Net中使用RedLock实现分布式锁


    ⒈简介

      RedLock 分布式锁算法由 Redis 的作者提出,大部分语言都有对应的实现,查看,RedLock.net 是 RedLock 分布式锁算法的 .NET 版实现,用来解决分布式下的并发问题。

      RedLock 的思想是使用多台 Redis Master ,节点之间完全独立,节点间不需要进行数据同步,因为 Master-Slave 架构一旦 Master 发生故障时数据没有复制到 Slave,被选为 Master 的 Slave 就丢掉了锁,另一个客户端就可以再次拿到锁。

      锁通过 setNX(原子操作) 命令设置,在有效时间内当获得锁的数量大于 (n/2+1) 代表成功,失败后需要向所有节点发送释放锁的消息。

      获取锁:

    1 SET resource_name my_random_value NX PX 30000

      释放锁:

    1 if redis.call("get",KEYS[1]) == ARGV[1] then
    2     return redis.call("del",KEYS[1])
    3 else
    4     return 0
    5 end

    ⒉使用

      1.创建 .NETCore API 项目

      2.Nuget 安装 RedLock.net

    1 Install-Package RedLock.net

      3.appsettings.json 添加 redis 配置

     1 {
     2   "Logging": {
     3     "LogLevel": {
     4       "Default": "Warning"
     5     }
     6   },
     7   "AllowedHosts": "*",
     8   "RedisUrls": [
     9     "127.0.0.1:6379",
    10     "192.168.214.128:6379"
    11   ]
    12 }

      4.添加 ProductService.cs,模拟商品购买

     1 // 有10个商品库存,如果同时启动多个API服务进行测试,这里改成存数据库或其他方式
     2 private static int stockCount = 10;
     3 public async Task<bool> BuyAsync()
     4 {
     5     // 模拟执行的逻辑代码花费的时间
     6     await Task.Delay(new Random().Next(100, 500));
     7     if (stockCount > 0)
     8     {
     9         stockCount--;
    10         return true;
    11     }
    12     return false;
    13 }

      5.修改 Startup.cs ,创建 RedLockFactory

        1.定义RedLockFactory属性

     1         private RedLockFactory lockFactory
     2         {
     3             get
     4             {
     5                 var redisUrls = Configuration.GetSection("RedisUrls").GetChildren().Select(s => s.Value).ToArray();
     6                 if(redisUrls.Length <= 0)
     7                 {
     8                     throw new ArgumentException("RedisUrl 不能为空");
     9                 }
    10                 var endPoints = new List<RedLockEndPoint>();
    11                 foreach (var item in redisUrls)
    12                 {
    13                     var arr = item.Split(":");
    14                     endPoints.Add(new DnsEndPoint(arr[0], Convert.ToInt32(arr[1])));
    15                 }
    16                 return RedLockFactory.Create(endPoints);
    17             }
    18         }

        2.在 ConfigureServices 注入 IDistributedLockFactory:

    1         // This method gets called by the runtime. Use this method to add services to the container.
    2         public void ConfigureServices(IServiceCollection services)
    3         {
    4             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    5             services.AddSingleton(typeof(IDistributedLockFactory), lockFactory);
    6             services.AddScoped(typeof(ProductService));
    7         }

        3.修改 Configure,应用程序结束时释放 lockFactory

     1         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
     2         public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
     3         {
     4             if (env.IsDevelopment())
     5             {
     6                 app.UseDeveloperExceptionPage();
     7             }
     8 
     9             app.UseMvc();
    10 
    11             lifetime.ApplicationStopping.Register(() =>
    12             {
    13                 lockFactory.Dispose();
    14             });
    15 
    16         }

      6.在 Controller 添加方法 DistributedLockTest

     1 private readonly IDistributedLockFactory _distributedLockFactory;
     2 private readonly ProductService _productService;
     3 
     4 public HomeController(IDistributedLockFactory distributedLockFactory,
     5     ProductService productService)
     6 {
     7     _distributedLockFactory = distributedLockFactory;
     8     _productService = productService;
     9 }
    10 
    11 [HttpGet]
    12 public async Task<bool> DistributedLockTest()
    13 {
    14     var productId = "id";
    15     // resource 锁定的对象
    16     // expiryTime 锁定过期时间,锁区域内的逻辑执行如果超过过期时间,锁将被释放
    17     // waitTime 等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
    18     // retryTime 等待时间内,多久尝试获取一次
    19     using (var redLock = await _distributedLockFactory.CreateLockAsync(productId, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(20)))
    20     {
    21         if (redLock.IsAcquired)
    22         {
    23             var result = await _productService.BuyAsync();
    24             return result;
    25         }
    26         else
    27         {
    28             Console.WriteLine($"获取锁失败:{DateTime.Now}");
    29         }
    30     }
    31     return false;
    32 }

      在文章RedLock 实现分布式锁基础之上修改部分代码编写。

      

      

  • 相关阅读:
    Scrapy框架-scrapy框架快速入门
    Scrapy框架-scrapy框架架构详解
    linux常用命令大全
    Redis常用命令大全
    centos7安装keepalived问题
    redis集群部署那点事
    centos7安装python3.6后导致防火墙功能无法正常工作的解决办法
    MySQL/Oracle视图的创建与使用
    通过sqoop将hdfs数据导入MySQL
    股票交易日定时爬取上交所/深交所所有股票行情数据存储到数据库
  • 原文地址:https://www.cnblogs.com/fanqisoft/p/10942753.html
Copyright © 2020-2023  润新知