在高併發的 PHP 應用中,進程鎖是防止競爭條件、保證數據一致性的關鍵機制。本文分享一個基於 Memcache 封裝的進程鎖類,支援自動重試、超時回調、連接復用等企業級特性,適合分佈式環境下的鎖控制場景。
該類封裝了鎖的獲取、釋放、重試邏輯及異常處理,主要屬性包括:
public function connect() {
if (!isset($this->oMemcache)) {
$this->oMemcache = new Memcache();
$this->oMemcache->connect('127.0.0.1', 11211);
}
return $this->oMemcache;
}
採用惰性初始化,確保全局僅建立一個連接,減少資源開銷。
public function addMemcache($sKey, $sValue, $iTimeout) {
for ($i = 0; $i < $this->iMemcacheRetryCount; $i++) {
$bRes = $this->oMemcache->add($sKey, $sValue, $iTimeout);
if ($bRes) return true;
usleep($this->iLockRetryInterval * 1000);
}
return false;
}
利用 Memcache add 命令的原子性(僅當 key 不存在時寫入成功)實現「檢查並設置」(CAS)語義,配合重試機制應對高併發搶鎖。
public function lock($sLockID) {
$oMemcache = $this->connect();
$sKey = $this->sLockKeyPre . $sLockID;
for ($i = 0; $i < $this->iLockRetryCount; $i++) {
if ($this->addMemcache($sKey, '1', $this->iLockCacheTimeout)) {
return true;
}
usleep($this->iLockRetryInterval * 1000);
}
// 重試耗盡,觸發超時回調
if (is_callable($this->onLockTimeoutFunc)) {
call_user_func($this->onLockTimeoutFunc);
}
return false;
}
public function unlock($sLockID) {
$oMemcache = $this->connect();
$sKey = $this->sLockKeyPre . $sLockID;
return $this->oMemcache->delete($sKey);
}
直接刪除 key 釋放鎖,簡單高效。生產環境建議加入「僅刪除自己持有的鎖」邏輯(如存入進程 ID 校驗),防止誤刪他人鎖。
$oLock = new lock_processlock();
$lockResource = "order_process_123";
// 獲取鎖
if ($oLock->lock($lockResource)) {
try {
// 執行核心業務:扣庫存、寫訂單、發 MQ 等
processOrder($lockResource);
} finally {
// 確保釋放鎖
$oLock->unlock($lockResource);
}
} else {
// 可選:記錄日誌、拋異常、排隊重試
logError("獲取鎖失敗: $lockResource");
}
$sValue = getmypid() . '_' . microtime(true),解鎖前校驗防止誤刪。本文提供的 lock_processlock 類結構清晰、功能完備,可直接應用於訂單處理、庫存扣減、定時任務防重等場景。理解其基於 Memcache add 原子特性的實現原理,有助於在更複雜的分佈式架構中設計更健壯的鎖機制。