詳解PHP中互斥鎖庫(kù)hyperf-wise-locksmith的使用
在分布式系統(tǒng)中,如何確保多臺(tái)機(jī)器之間不會(huì)產(chǎn)生競(jìng)爭(zhēng)條件,是一個(gè)常見且重要的問題。hyperf-wise-locksmith
庫(kù)作為 Hyperf
框架中的一員,提供了一個(gè)高效、簡(jiǎn)潔的互斥鎖解決方案。
本文將帶你了解這個(gè)庫(kù)的安裝、特性、基本與高級(jí)功能,并結(jié)合實(shí)際應(yīng)用場(chǎng)景,展示其在項(xiàng)目中的應(yīng)用。
hyperf-wise-locksmith 庫(kù)簡(jiǎn)介
hyperf-wise-locksmith
是一個(gè)適配 Hyperf 框架的互斥鎖庫(kù),它基于 pudongping/wise-locksmith
庫(kù)構(gòu)建。它可以幫助我們?cè)诜植际江h(huán)境下進(jìn)行鎖的管理,確保同一時(shí)刻只有一個(gè)進(jìn)程能夠操作某些共享資源,從而避免數(shù)據(jù)的競(jìng)爭(zhēng)和不一致問題。
安裝
要在你的 Hyperf 項(xiàng)目中使用 hyperf-wise-locksmith
,你需要通過 Composer 進(jìn)行安裝:
composer require pudongping/hyperf-wise-locksmith -vvv
確保你的環(huán)境滿足以下要求:
- PHP >= 8.0
- hyperf ~3.0.0。
特性
hyperf-wise-locksmith
提供了多種鎖機(jī)制,包括文件鎖、分布式鎖、紅鎖和協(xié)程級(jí)別的互斥鎖。這些鎖機(jī)制可以幫助開發(fā)者在不同的場(chǎng)景下保護(hù)共享資源,避免競(jìng)態(tài)條件。
基本功能
文件鎖(flock)
文件鎖是一種簡(jiǎn)單的鎖機(jī)制,它依賴于文件系統(tǒng)。以下是一個(gè)使用文件鎖的示例:
private function flock(float $amount) { $path = BASE_PATH . '/runtime/alex.lock.cache'; $fileHandler = fopen($path, 'a+'); // fwrite($fileHandler, sprintf("%s - %s \r\n", 'Locked', microtime())); $res = $this->locker->flock($fileHandler, function () use ($amount) { return $this->deductBalance($amount); }); return $res; }
分布式鎖(redisLock)
分布式鎖適用于分布式系統(tǒng),它依賴于 Redis。以下是一個(gè)使用分布式鎖的示例:
private function redisLock(float $amount) { $res = $this->locker->redisLock('redisLock', function () use ($amount) { return $this->deductBalance($amount); }, 10); return $res; }
高級(jí)功能
紅鎖(redLock)
紅鎖是一種更安全的分布式鎖實(shí)現(xiàn),它需要多個(gè) Redis 實(shí)例。以下是一個(gè)使用紅鎖的示例:
private function redLock(float $amount) { $res = $this->locker->redLock('redLock', function () use ($amount) { return $this->deductBalance($amount); }, 10); return $res; }
協(xié)程級(jí)別的互斥鎖(channelLock)
協(xié)程級(jí)別的互斥鎖適用于協(xié)程環(huán)境,它提供了一種輕量級(jí)的鎖機(jī)制。以下是一個(gè)使用協(xié)程鎖的示例:
private function channelLock(float $amount) { $res = $this->locker->channelLock('channelLock', function () use ($amount) { return $this->deductBalance($amount); }); return $res; }
實(shí)際應(yīng)用場(chǎng)景
假設(shè)我們有一個(gè)在線支付系統(tǒng),需要在多個(gè)請(qǐng)求中扣減用戶的余額。如果不使用互斥鎖,可能會(huì)導(dǎo)致超扣或扣減失敗。使用 hyperf-wise-locksmith
庫(kù),我們可以確保每次扣減操作都是原子性的。
代碼示例
以下是一個(gè)扣減用戶余額的示例,使用了 hyperf-wise-locksmith
庫(kù):
<?php declare(strict_types=1); namespace App\Services; use Hyperf\Contract\StdoutLoggerInterface; use Pudongping\HyperfWiseLocksmith\Locker; use Pudongping\WiseLocksmith\Exception\WiseLocksmithException; use Pudongping\WiseLocksmith\Support\Swoole\SwooleEngine; use Throwable; class AccountBalanceService { /** * 用戶賬戶初始余額 * * @var float|int */ private float|int $balance = 10; public function __construct( private StdoutLoggerInterface $logger, private Locker $locker ) { $this->locker->setLogger($logger); } private function deductBalance(float|int $amount) { if ($this->balance >= $amount) { // 模擬業(yè)務(wù)處理耗時(shí) usleep(500 * 1000); $this->balance -= $amount; } return $this->balance; } /** * @return float */ private function getBalance(): float { return $this->balance; } public function runLock(int $i, string $type, float $amount) { try { $start = microtime(true); switch ($type) { case 'flock': $this->flock($amount); break; case 'redisLock': $this->redisLock($amount); break; case 'redLock': $this->redLock($amount); break; case 'channelLock': $this->channelLock($amount); break; case 'noMutex': default: $this->deductBalance($amount); break; } $balance = $this->getBalance(); $id = SwooleEngine::id(); $cost = microtime(true) - $start; $this->logger->notice('[{type} {cost}] ==> [{i}<=>{id}] ==> 當(dāng)前用戶的余額為:{balance}', compact('type', 'i', 'balance', 'id', 'cost')); return $balance; } catch (WiseLocksmithException|Throwable $e) { return sprintf('Err Msg: %s ====> %s', $e, $e->getPrevious()); } } }
然后我們?cè)賹懸粋€(gè)控制器進(jìn)行調(diào)用
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use App\Services\AccountBalanceService; use Hyperf\Coroutine\Parallel; use function \Hyperf\Support\make; #[AutoController] class BalanceController extends AbstractController { // curl '127.0.0.1:9511/balance/consumer?type=noMutex' public function consumer() { $type = $this->request->input('type', 'noMutex'); $amount = (float)$this->request->input('amount', 1); $parallel = new Parallel(); $balance = make(AccountBalanceService::class); // 模擬 20 個(gè)并發(fā) for ($i = 1; $i <= 20; $i++) { $parallel->add(function () use ($balance, $i, $type, $amount) { return $balance->runLock($i, $type, $amount); }, $i); } $result = $parallel->wait(); return $this->response->json($result); } }
當(dāng)我們?cè)L問 /balance/consumer?type=noMutex
地址時(shí),我們可以看到用戶的余額會(huì)被扣成負(fù)數(shù),這明顯不符合邏輯。 然而當(dāng)我們?cè)L問下面幾個(gè)地址時(shí),我們可以看到用戶余額不會(huì)被扣成負(fù)數(shù),則說明很好的保護(hù)了競(jìng)態(tài)下的共享資源的準(zhǔn)確性。
/balance/consumer?type=flock
:文件鎖/balance/consumer?type=redisLock
:分布式鎖/balance/consumer?type=redLock
:紅鎖/balance/consumer?type=channelLock
:協(xié)程級(jí)別的互斥鎖
注意
關(guān)于使用到 redisLock
和 redLock
時(shí):
- 使用
redisLock
默認(rèn)采用的config/autoload/redis.php
配置文件中的第一個(gè)key
配置 redis 實(shí)例(即 default)??砂葱鑲魅氲?4 個(gè)參數(shù)string|null $redisPoolName
進(jìn)行重新指定。 - 使用
redLock
默認(rèn)采用的config/autoload/redis.php
配置文件中的所有key
對(duì)應(yīng)的配置 redis 實(shí)例。可按需傳入第 4 個(gè)參數(shù)?array $redisPoolNames = null
進(jìn)行重新指定。
文檔
詳細(xì)文檔可見 pudongping/wise-locksmith。
結(jié)語(yǔ)
hyperf-wise-locksmith
庫(kù)為 Hyperf 框架的開發(fā)者提供了強(qiáng)大的互斥鎖功能,可以幫助我們?cè)诟卟l(fā)場(chǎng)景下保護(hù)共享資源。
通過本文的介紹,希望你能對(duì) hyperf-wise-locksmith
有一個(gè)全面的了解,并在你的項(xiàng)目中靈活運(yùn)用。如果你覺得這個(gè)庫(kù)對(duì)你有幫助,希望你可以幫忙點(diǎn)個(gè) Star 喲~
以上就是詳解PHP中互斥鎖庫(kù)hyperf-wise-locksmith的使用的詳細(xì)內(nèi)容,更多關(guān)于PHP hyperf-wise-locksmith的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
php回調(diào)函數(shù)處理數(shù)組操作示例
這篇文章主要介紹了php回調(diào)函數(shù)處理數(shù)組操作,結(jié)合實(shí)例形式詳細(xì)分析了PHP回調(diào)函數(shù)遍歷與過濾數(shù)組相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2020-04-04如何從一個(gè)php文件向另一個(gè)地址post數(shù)據(jù),不用表單和隱藏的變量的
如何從一個(gè)php文件向另一個(gè)地址post數(shù)據(jù),不用表單和隱藏的變量的...2007-03-03自動(dòng)把純文本轉(zhuǎn)換成Web頁(yè)面的php代碼
用PHP來(lái)快速將純ASCII文本完美地轉(zhuǎn)換成為可讀的HTML標(biāo)記。2009-08-08PHP實(shí)現(xiàn)的簡(jiǎn)單對(duì)稱加密與解密方法實(shí)例小結(jié)
這篇文章主要介紹了PHP實(shí)現(xiàn)的簡(jiǎn)單對(duì)稱加密與解密方法,結(jié)合實(shí)例形式總結(jié)了常見的php對(duì)稱加密與解密操作方法,需要的朋友可以參考下2017-08-08解析PHP自帶的進(jìn)位制之間的轉(zhuǎn)換函數(shù)
本篇文章是對(duì)PHP自帶的進(jìn)位制之間的轉(zhuǎn)換函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06