天天看點

基于Redis的分布式鎖(不公平鎖)基于Redis的分布式鎖(不公平鎖)

[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循環

    get Lock

    和while中的$time=time()對比,如果差大于2秒則為逾時, 直接

    del Lock

    ,然後

    Setnx Lock $time

  • 如果setnx成功,則為加鎖成功,開始執行邏輯

    decr phone_count

    ,如果這個過程執行超過了2秒,必然會被後面來的

    del Lock

  • 是以在邏輯執行完畢之後, 此時我們再次

    get Lock

    檢視Redis的時間戳是否是$time,如果不相等則復原事物.
  • 如果相等, 再對比目前時間戳和

    get Lock

    内容,如果差小于2秒,判斷decr的傳回值如果大于等于0則提示success同時

    del Lock

    .
  • 如果目前時間戳和Lock的内容差大于2或者和之前儲存的時間戳不是同一個.則提示搶購失敗.或者decr的結果小于等于0,則提示搶購完畢.

如果要做公平鎖的話就需要用到zset的zadd等有序隊列的指令

可以使用Redis指令中混合lua的形式

這篇博文是真的不錯, 一直關注部落客, 跟随部落客學習好多年了.

飛鴻影的部落格-Redis使用lua腳本

看完上面的部落格之後,結合上面說的分布式鎖的思路, 一套基于redis的lua腳本的形式的完成的分布式鎖的代碼就出現了. 這裡就不累述了

轉載于:https://my.oschina.net/chinaliuhan/blog/3084455