日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

使用Redis创建分布式锁

發布時間:2023/12/4 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用Redis创建分布式锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
點擊上方藍色字關注我們~


在本文中,我們將討論如何在.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创建分布式锁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。