本文將闡述在redis裡頭構建分布式鎖與訊號量時關注的點。
redis共有五種基礎資料結構,字串(string),集合(set),列表(list),雜湊(hash)和有序集合(zset)。
分布式鎖相較於鎖來說,有幾個問題需要解決:
1、 持有鎖的程序因操作過長,導致自身的鎖被釋放,但是自身並不知曉這一點;
2、 持有鎖的程序因操作過長不能及時釋放鎖,導致其他程序無法獲取鎖;
3、 在乙個整合持有的鎖過期後,其他多個程序都可能嘗試去獲取鎖,並且都獲取到了鎖。
解決分布式鎖的關鍵還是提供:超時機制,關鍵節點加上本地鎖。
可以簡單的通過使用redis提供的setex命令實現基本的鎖功能,但是無分布式鎖常見的一些高階特性,比如超時時限等。
簡易鎖:通過setex方法設定值來設計鎖,並且監控鎖是否會發生變化(redis中客戶端可以訪問鎖),一旦發生變化進行鎖的消除。
在給鎖增加超時時限設定時,會在程式取得鎖之後呼叫expire命令設定過期時間,但如果在獲取鎖與呼叫expire之間執行緒崩潰則該鎖就無法釋放了。因此,每當客戶端在獲取執行緒失敗後會對請求的鎖設定超時時限(由請求的客戶端設定,條件是沒有超時時限),最終鎖就會帶有超時時間,並且最終會因為時間超時而釋放,其它的客戶端就可以繼續使用已經被釋放的鎖了。可能會存在多個客戶端同時設定超時時限,但是鎖的超時時間也不會產生太多變化。
訊號量相較於鎖來說,鎖允許乙個客戶端訪問,而訊號量是允許多個客戶端同時訪問,兩者的區別在於同時訪問的客戶端數量,那麼如何選擇哪些客戶端可以先訪問,在客戶端使用完畢後,如何歸還訊號量;和鎖相同,也是需要考慮訊號量的超時時限問題,執行緒奔潰訊號量如何**問題。
用redis構建訊號量,主要是採用計數器+有序集合來構建,可以構建簡易訊號量,公平訊號量和重新整理訊號量。考慮的因素是客戶端首先是通過計算器的自增操作獲取客戶端在有序集合的排名,之後進入有序集合的排名,但是獲取計數器的計算值與進入有序集合並不是乙個原子操作,可能存在相互竊取訊號量的問題。
具體的訊號量獲取操作是:
1、去除超時訊號量,有兩個有序集合(1、超時有序集合,儲存的是客戶端的超時時限;2訊號量擁有者有序集合,是客戶端的排名,用以判斷訊號量又擁有者客戶端【排名必須要低】),首先移除超時有序集合中的超時客戶端,之後兩個集合做交集並將結果儲存在訊號量擁有者有序集合中。【流水線事務操作的】
2、 呼叫計數器進行自增操作,並將計算器生成的值新增到訊號量擁有者有序集合中,並新增客戶端(當前的系統時間)到超時有序集合,如果排名足夠低能夠獲取訊號量,則成功獲取訊號量。【流水線操作】
3、 如果沒有獲取訊號量,那麼則需要從訊號量擁有者有序集合和超時有序集合中移除和客戶端相關的元素。【流水線事務操作】
【備註,redis的事務處理操作特性:1、要不全部執行成功,要不全部不執行;2、redis的事務處理時不受其他redis的執行命令影響】
當持有訊號量的客戶端需要延長訊號量持有時間時,需要重新整理訊號量,顯然從前面的闡述中得知,只需要將超時有序集合中系統時間進行重新整理即可。
訊號量之間也是存在一定的競爭條件,從上面可以得知,redis的訊號量獲取主要是分為三個步驟:
redis原始碼學習 程式設計技巧
巨集的用法 define version 6.0.1 define datetime datetime 將變數 s 以字串的形式輸出 define xstr s str s define str s s 使用巨集拼接字串 define echo str jemalloc xstr hello xst...
flannel 實戰與原始碼分析(七)
這是flannel最後一篇,我原本不準備介紹udp,因為這種方案的網路損耗實在是太多,大約一半損耗,vxlan大約是30 損耗。但基本的udp使用我還是想和大家分享一下的,主要是tun裝置的使用。像udp的registernetwork和vxlan一樣,我就不單獨說了backend udp udp ...
redis原始碼 (九)Redis
前些天主要看了redis底層依賴的一些資料結構和事件管理庫的 比較零散,但大體上了解了作者的設計思路.對不同規模 n 的資料採用不同的資料結構以實現對記憶體利用的 最優 這裡的最優我想作者也沒有做過嚴格的實驗,不同的應用場景在redis上的表現肯定有所不同,如果有必要,可以再配置檔案中對一些閾值做調...