PHP DIY 系列------應用篇:1. 分散式鎖

13sai發表於2020-02-25

含義

為了防止分散式系統中的多個程式之間相互干擾,我們需要一種分散式協調技術來對這些程式進行排程。而這個分散式協調技術的核心就是來實現這個分散式鎖。

分析

  • 在分散式系統環境下,一個方法在同一時間只能被一個機器的一個執行緒執行
  • 高可用的獲取鎖與釋放鎖
  • 高效能的獲取鎖與釋放鎖
  • 具備可重入特性(可理解為重新進入,由多於一個任務併發使用,而不必擔心資料錯誤)
  • 具備鎖失效機制,防止死鎖
  • 具備非阻塞鎖特性,即沒有獲取到鎖將直接返回獲取鎖失敗

實現方式

常見的有:

  • 基於Redis
  • 基於mysql
  • 基於Zookeeper

具體實現

考慮到我們使用的PHP語言,簡單結合Redis來實現一下分散式鎖。

我們來畫個簡單的原理圖:

image

原理十分簡單,那麼我們如何實現呢?

這裡我們用到兩個知識點:

  • Redis的setnx方法
  • php的register
function processLock($redis, $key, $ttl = 5)
{
    $ret = $redis->setnx($key, 1);
    if ($ret) {
        $redis->expire($key, $ttl);

        register_shutdown_function(function () use ($redis, $key){
            $redis->del($key);
            });
    }

    return $ret;
}

demo裡的$redis是一個redis例項,我們在前面已經實現過,不多說明。

加鎖

我們使用的setnx命令,senx表示“SET if Not eXists”,如果key不存在,則不set,如果存在,則set

redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0
redis> GET mykey
"Hello"

解鎖

使用的是del,即刪除這個key。這裡結合了 register_shutdown_function — 註冊一個會在php中止時執行的函式,設定了之後我們就可以不必手動去解鎖

鎖超時

這裡給鎖加了一個expire過期時間5秒,目的是防止使用這個方法之後的執行了“神奇”程式碼丟擲了語法錯誤,導致register_shutdown_function裡的程式碼沒有執行,雖然請求結束,但是加鎖後,沒有解鎖,影響了後續請求。

問題

  • 加入setnx之後expire之前程式異常了怎麼辦?
本作品採用《CC 協議》,轉載必須註明作者和本文連結

分享開發知識,歡迎交流。qq957042781

相關文章