[TOC]
基于Redis的分布式鎖(不公平鎖)
鎖的應用場景
Redis其實是有事務功能的,但是Redis的事務不能復原,具體原因就忘了,有興趣可以看下<Redis設計與實作(第二版)>這本書.
分布式事務不會應用在MySQL等資料庫中,因為這種資料庫已經有完美的事務和鎖機制了.
主要用在, 比如在叢集機器搶購時,你沒有使用Redis隊列,而是在Redis的string定義一個數字作為商品總量.比如
set phone_count 10000
台手機.
這時候如果出現并發修改(肯定會有并發),比如10個使用者同時修改該字段
decr phone_count
可能是不準确的,因為可能會很多人都在修改.
這時候就需要我們自己來實作一套基于Redis鎖機制,悲觀鎖.
鎖的實作介紹
Redis的所有指令都是具有原子性的,之是以說要用鎖,是因為可能有多個使用者同時修改,那麼我們的得到的資料就會是不準确的.
- Ggetset: 字段存在時同時傳回字段的内容
- Setnx: 字段存在時,set會失敗
- Decr: 會出現小于0的負數情況
假定,逾時時間為2秒.
假定商品數量為1000台
set phone_count 1000
-
如果傳回值小于等于零,直接提示已搶完.get phone_count
- 直接聲明$time=time()嘗試進行加鎖,
Setnx Lock $time
- 如果setnx失敗,說明已有鎖,執行while循環
和while中的$time=time()對比,如果差大于2秒則為逾時, 直接get Lock
,然後del Lock
Setnx Lock $time
- 如果setnx成功,則為加鎖成功,開始執行邏輯
,如果這個過程執行超過了2秒,必然會被後面來的decr phone_count
掉del Lock
- 是以在邏輯執行完畢之後, 此時我們再次
檢視Redis的時間戳是否是$time,如果不相等則復原事物.get Lock
- 如果相等, 再對比目前時間戳和
内容,如果差小于2秒,判斷decr的傳回值如果大于等于0則提示success同時get Lock
.del Lock
- 如果目前時間戳和Lock的内容差大于2或者和之前儲存的時間戳不是同一個.則提示搶購失敗.或者decr的結果小于等于0,則提示搶購完畢.
如果要做公平鎖的話就需要用到zset的zadd等有序隊列的指令
可以使用Redis指令中混合lua的形式
這篇博文是真的不錯, 一直關注部落客, 跟随部落客學習好多年了.
飛鴻影的部落格-Redis使用lua腳本
看完上面的部落格之後,結合上面說的分布式鎖的思路, 一套基于redis的lua腳本的形式的完成的分布式鎖的代碼就出現了. 這裡就不累述了
轉載于:https://my.oschina.net/chinaliuhan/blog/3084455