[擴充套件] Hyperf-redis-lock 基於hyperf的分散式鎖的實現

南城以南發表於2021-10-18

English | 中文
一個簡單的Redis分散式鎖的實現 基於Hyperf框架。本擴充套件實現了基本的分散式鎖,支援阻塞式分散式鎖和非阻塞式分散式鎖。

原理

Redis的命令為原子性 使用Redisset即可保證業務的序列執行。
2.8之前版本的Redis不支援setex選項 因此只能使用 setnx+expire的方式。 對應擴充套件1.0版本.
2.8之後版本的Redis可以直接使用 setnx+ex選項。對應擴充套件2.*版本

因此 2.版本只支援2.8版本以後的Redis 1.版本支援所有版本的Redis.

確認你的Redis版本 如果你的Redis低於 2.8版本 則set 命令不支援 ex選項 因此你需要安裝1.x版本。

您可以執行下面命令檢視redis的版本。
redis-server --version

安裝

注意:請根據你的Redis版本
執行 composer require lysice/hyperf-redis-lock

Redis版本 set ex支援 引入版本
<2.8 不支援 1.*
>=2.8 支援 2.* 1.*均可

使用

首先需要在程式內初始化你需要的redis

/**
 * @var RedisLock 
 */ 
 protected $redis;
 public function __construct(RedisFactory $redisFactory) {
     $this->redis = $redisFactory->get('default'); 
 }
  • 非阻塞式鎖 該方法在嘗試獲取鎖之後直接返回結果。

    • 若獲取到鎖則執行閉包後返回結果。
    • 獲取鎖失敗時 預設返回false。您也可以指定可選引數 $finally 該引數為一個閉包 當獲取鎖失敗時 若指定該閉包 則直接返回該閉包的結果。
      public function testNonBlocking(ResponseInterface $response)
      { 
      // 初始化RedisLock 引數:redis例項 鎖名稱 超時時間
      $lock = new RedisLock($this->redis, 'lock', 20); // 非阻塞式獲取鎖
      $res = $lock->get(function () { sleep(10); return [123]; }); return $response->json($res); 
      }
  • 阻塞式鎖 該方法首先嚐試獲取鎖,若獲取失敗 則每隔250毫秒獲取一次 直到超時(等待時間超出本程式內鎖的過期時間 則判定為超時)。如果鎖獲取成功 則執行閉包函式返回結果。

    • 注意 若超時 則程式會丟擲LockTimeoutException超時異常。應用程式內需要自己捕獲該異常以便處理超時情況的返回結果。
    • 例子:
/**
 * @return \Psr\Http\Message\ResponseInterface 
 */
public function testBlocking(ResponseInterface $response) {
    try { 
    // 初始化RedisLock 引數:redis例項 鎖名稱 超時時間
    $lock = new RedisLock($this->redis, 'lock', 4); 
    // 阻塞式
    $res = $lock->block(4, function () {
           return [456]; 
    }); 
    return $response->json(['res' => $res]); 
    // 捕獲超時異常 超時處理
   } catch (LockTimeoutException $exception) { 
       var_dump('lockA lock check timeout');
       return $response->json(['res' => false, 'message' => '超時']);
   }
 }

最後

程式碼貢獻

如果存在任何好的想法請提交pull request

程式碼問題

如果存在任何問題請提交issue.

本作品採用《CC 協議》,轉載必須註明作者和本文連結
風起於青萍之末 浪成於微瀾之間

相關文章