含義
為了防止分散式系統中的多個程式之間相互干擾,我們需要一種分散式協調技術來對這些程式進行排程。而這個分散式協調技術的核心就是來實現這個分散式鎖。
分析
- 在分散式系統環境下,一個方法在同一時間只能被一個機器的一個執行緒執行
- 高可用的獲取鎖與釋放鎖
- 高效能的獲取鎖與釋放鎖
- 具備可重入特性(可理解為重新進入,由多於一個任務併發使用,而不必擔心資料錯誤)
- 具備鎖失效機制,防止死鎖
- 具備非阻塞鎖特性,即沒有獲取到鎖將直接返回獲取鎖失敗
實現方式
常見的有:
- 基於Redis
- 基於mysql
- 基於Zookeeper
具體實現
考慮到我們使用的PHP語言,簡單結合Redis來實現一下分散式鎖。
我們來畫個簡單的原理圖:
原理十分簡單,那麼我們如何實現呢?
這裡我們用到兩個知識點:
- 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 協議》,轉載必須註明作者和本文連結