47人参与 • 2025-02-13 • Php
在分布式系统中,如何确保多台机器之间不会产生竞争条件,是一个常见且重要的问题。hyperf-wise-locksmith
库作为 hyperf
框架中的一员,提供了一个高效、简洁的互斥锁解决方案。
本文将带你了解这个库的安装、特性、基本与高级功能,并结合实际应用场景,展示其在项目中的应用。
hyperf-wise-locksmith
是一个适配 hyperf 框架的互斥锁库,它基于 pudongping/wise-locksmith
库构建。它可以帮助我们在分布式环境下进行锁的管理,确保同一时刻只有一个进程能够操作某些共享资源,从而避免数据的竞争和不一致问题。
要在你的 hyperf 项目中使用 hyperf-wise-locksmith
,你需要通过 composer 进行安装:
composer require pudongping/hyperf-wise-locksmith -vvv
确保你的环境满足以下要求:
hyperf-wise-locksmith
提供了多种锁机制,包括文件锁、分布式锁、红锁和协程级别的互斥锁。这些锁机制可以帮助开发者在不同的场景下保护共享资源,避免竞态条件。
文件锁是一种简单的锁机制,它依赖于文件系统。以下是一个使用文件锁的示例:
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; }
分布式锁适用于分布式系统,它依赖于 redis。以下是一个使用分布式锁的示例:
private function redislock(float $amount) { $res = $this->locker->redislock('redislock', function () use ($amount) { return $this->deductbalance($amount); }, 10); return $res; }
红锁是一种更安全的分布式锁实现,它需要多个 redis 实例。以下是一个使用红锁的示例:
private function redlock(float $amount) { $res = $this->locker->redlock('redlock', function () use ($amount) { return $this->deductbalance($amount); }, 10); return $res; }
协程级别的互斥锁适用于协程环境,它提供了一种轻量级的锁机制。以下是一个使用协程锁的示例:
private function channellock(float $amount) { $res = $this->locker->channellock('channellock', function () use ($amount) { return $this->deductbalance($amount); }); return $res; }
假设我们有一个在线支付系统,需要在多个请求中扣减用户的余额。如果不使用互斥锁,可能会导致超扣或扣减失败。使用 hyperf-wise-locksmith
库,我们可以确保每次扣减操作都是原子性的。
代码示例
以下是一个扣减用户余额的示例,使用了 hyperf-wise-locksmith
库:
<?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) { // 模拟业务处理耗时 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}] ==> 当前用户的余额为:{balance}', compact('type', 'i', 'balance', 'id', 'cost')); return $balance; } catch (wiselocksmithexception|throwable $e) { return sprintf('err msg: %s ====> %s', $e, $e->getprevious()); } } }
然后我们再写一个控制器进行调用
<?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 个并发 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); } }
当我们访问 /balance/consumer?type=nomutex
地址时,我们可以看到用户的余额会被扣成负数,这明显不符合逻辑。 然而当我们访问下面几个地址时,我们可以看到用户余额不会被扣成负数,则说明很好的保护了竞态下的共享资源的准确性。
/balance/consumer?type=flock
:文件锁/balance/consumer?type=redislock
:分布式锁/balance/consumer?type=redlock
:红锁/balance/consumer?type=channellock
:协程级别的互斥锁关于使用到 redislock
和 redlock
时:
redislock
默认采用的 config/autoload/redis.php
配置文件中的第一个 key
配置 redis 实例(即 default)。可按需传入第 4 个参数 string|null $redispoolname
进行重新指定。redlock
默认采用的 config/autoload/redis.php
配置文件中的所有 key
对应的配置 redis 实例。可按需传入第 4 个参数 ?array $redispoolnames = null
进行重新指定。详细文档可见 pudongping/wise-locksmith。
hyperf-wise-locksmith
库为 hyperf 框架的开发者提供了强大的互斥锁功能,可以帮助我们在高并发场景下保护共享资源。
通过本文的介绍,希望你能对 hyperf-wise-locksmith
有一个全面的了解,并在你的项目中灵活运用。如果你觉得这个库对你有帮助,希望你可以帮忙点个 star 哟~
以上就是详解php中互斥锁库hyperf-wise-locksmith的使用的详细内容,更多关于php hyperf-wise-locksmith的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论