詳解Redis分散式鎖
導讀 |
最近首度應用"分散式鎖",現在想想,分散式鎖不是孤立的技能點,這其實就是跨主機的執行緒同步。
|
最近首度應用"分散式鎖",現在想想,分散式鎖不是孤立的技能點,這其實就是跨主機的執行緒同步。
單機伺服器可以透過共享某堆記憶體來標記上鎖/解鎖,執行緒同步說到底是建立在單機作業系統的使用者態/核心態對共享記憶體的訪問控制。
而分散式伺服器不是在同一臺機器上:跨主機,因此需要將鎖標記儲存在所有機器程式都能看到的地方。
在開發很多業務場景會使用到鎖,例如庫存控制,抽獎等。
例如庫存只剩1個商品,有三個使用者同時打算購買,誰先購買庫存立即清零,不能讓其他二人也購買成功。
我們常說的執行緒安全、執行緒同步方案,包括此次的分散式鎖都是基於
“多執行緒/多程式對特定資源同時有更新操作”。
- 分散式系統,一個鎖在同一時間只能被一個伺服器獲取 (這是分散式鎖的基礎)
- 具備鎖失效機制,防止死鎖 (防止某些意外,鎖沒有得到釋放,別人也無法得到鎖)
Redis SET resource-name anystring NX EX max-lock-time
是一種最簡單的分散式鎖實現方案。
SET 支援多個引數:
- EX seconds-- 設定過期時間(s)
- NX -- 如果key不存在,則設定 ......
因為SET 引數可以替代SETNX,SETEX,GETSET,這些命令在未來可能被廢棄。
上面的命令返回OK(或經過重試),客戶端就獲取到這個鎖;
使用DEL命令解鎖;到達超時時間會自動釋放鎖。
在解鎖時,增加一些設計,讓系統更加健壯:
3.不要使用固定的String值作為鎖標記值,而是使用一個不易被猜中的隨機值, 業內稱為token
4.不使用DEL命令釋放鎖,而是傳送script去移除key
第3、4點是為了解決 :“鎖提前過期,客戶端A還沒有執行完,然後客戶端B獲取了鎖,這時客戶端A執行完了,會不會在刪鎖的時候把B的鎖給刪掉” -- 4是3技術上的推薦實現。
如下:
if redis.call("get",KEYS1] ==ARGV[1]) then return redis.call("DEL",KEYS[1]) else return 0 end
下面使用StackExchange.Redis 寫了基於以上考量的程式碼示例:
////// Acquires the lock. ////// /// 隨機值 /// /// 非阻塞鎖 static bool Lock(string key, string token,int expireSecond=10, double waitLockSeconds = 0) { var waitIntervalMs = 50; bool isLock; DateTime begin = DateTime.Now; do { isLock = Connection.GetDatabase().StringSet(key, token, TimeSpan.FromSeconds(expireSecond), When.NotExists); if (isLock) return true; //不等待鎖則返回 if (waitLockSeconds == 0) break; //超過等待時間,則不再等待 if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds) break; Thread.Sleep(waitIntervalMs); } while (!isLock); return false; } ////// Releases the lock. //////true, if lock was released,falseotherwise./// Key. /// value static bool UnLock(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; } } private static LazylazyConnection = new Lazy(() => { ConfigurationOptions configuration = new ConfigurationOptions { AbortOnConnectFail = false, ConnectTimeout = 5000, }; configuration.EndPoints.Add("10.100.219.9", 6379); return ConnectionMultiplexer.Connect(configuration.ToString()); }); public static ConnectionMultiplexer Connection => lazyConnection.Value;
以上程式碼新增了第五點考量:
5. 為避免無限制搶鎖,增加了非阻塞鎖:輪詢_s等待鎖,未等到則不再搶鎖
下面並行開啟三個任務,同時減少庫存:
static void Main(string[] args) { // 嘗試並行執行3個任務 Parallel.For(0, 3, x => { string token = $"loki:{x}"; bool isLocked = Lock("loki", token, 5, 10); if (isLocked) { Console.WriteLine($"{token} begin reduce stocks (with lock) at {DateTime.Now}."); Thread.Sleep(1000); Console.WriteLine($"{token} release lock {UnLock("loki", token)} at {DateTime.Now}. "); } else { Console.WriteLine($"{token} begin reduce stocks at {DateTime.Now}."); } }); }
可以看到三個並行任務依次獲取/釋放鎖
本文從基礎的執行緒安全、執行緒同步,認識到分散式鎖是跨主機的資源執行緒/程式同步方案, 以步步為營的風格 演示了RedisSET命令做分散式鎖的設計考量,好記性不如爛筆頭。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2778485/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 詳解 Redis 分散式鎖的 5 種方案Redis分散式
- Redis分散式鎖解決方案Redis分散式
- Redis 分散式鎖解決方案Redis分散式
- 十九、Redis分散式鎖、Zookeeper分散式鎖Redis分散式
- 面試題詳解:如何用Redis實現分散式鎖?面試題Redis分散式
- 分散式鎖-Redis分散式Redis
- Redis 分散式鎖Redis分散式
- Redis分散式鎖Redis分散式
- Redis 分散式鎖(一)Redis分散式
- Redis分散式鎖解析Redis分散式
- redis系列:分散式鎖Redis分散式
- redis分散式鎖-可重入鎖Redis分散式
- Redis分散式鎖加鎖案例Redis分散式
- 高併發架構系列:分散式鎖的由來、特點及Redis分散式鎖的實現詳解架構分散式Redis
- 細說Redis分散式鎖?Redis分散式
- Redis分散式鎖實戰Redis分散式
- 分散式鎖----Redis實現分散式Redis
- Redis 應用-分散式鎖Redis分散式
- Redis實現分散式鎖Redis分散式
- 基於 Redis 分散式鎖Redis分散式
- 【Redis】利用 Redis 實現分散式鎖Redis分散式
- redis分散式鎖-spring boot aop+自定義註解實現分散式鎖Redis分散式Spring Boot
- Redis分散式鎖解決搶購問題Redis分散式
- Redis面試系列:Redis實現分散式鎖Redis面試分散式
- Redis之分散式鎖實現Redis分散式
- 分散式鎖之Redis實現分散式Redis
- redis分散式鎖-java實現Redis分散式Java
- Redis如何實現分散式鎖Redis分散式
- 分散式鎖--Redis小試牛刀分散式Redis
- 分散式鎖實現(一):Redis分散式Redis
- 利用Redis實現分散式鎖Redis分散式
- redis分散式鎖的實現Redis分散式
- 基於 Redis 的分散式鎖Redis分散式
- 基於redis的分散式鎖Redis分散式
- redis分散式鎖-SETNX實現Redis分散式
- 使用 Redis 實現分散式鎖Redis分散式
- Redis分散式鎖服務(八)Redis分散式
- 用Redis構建分散式鎖Redis分散式