English | 中文
一個簡單的Redis分散式鎖的實現 基於Hyperf框架。本擴充套件實現了基本的分散式鎖,支援阻塞式分散式鎖和非阻塞式分散式鎖。
原理
Redis
的命令為原子性 使用Redis
的set
即可保證業務的序列執行。2.8
之前版本的Redis
不支援set
的ex
選項 因此只能使用 setnx+expire
的方式。 對應擴充套件1.0版本.2.8
之後版本的Redis
可以直接使用 set
的nx+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 協議》,轉載必須註明作者和本文連結