在.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 實現分布式鎖基礎之上修改部分代碼編寫。

 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM