remi-san / lock
锁定库
Requires
- php: >=5.5
- ext-redis: *
- psr/log: ^1.0
- symfony/stopwatch: ^2.6|^3.1
Requires (Dev)
- mockery/mockery: ^0.9
- phpunit/phpunit: ^4.5
- squizlabs/php_codesniffer: ^2.0
This package is auto-updated.
Last update: 2024-09-21 22:12:25 UTC
README
描述
Lock
是一个旨在提供简单且可靠地锁定资源的库。
主要类
-
RemiSan\Lock\Locker
提供一个包含以下方法的接口lock
用于锁定资源一段时间(ttl
- 非必需),允许在成功之前重试一定次数。isLocked
用于检查资源是否仍然被锁定。unlock
用于解锁资源。
-
RemiSan\Lock\Lock
提供一个结构来存储关于锁的信息resource
已被锁定的资源token
由Locker
生成的令牌(使用RemiSan\Lock\TokenGenerator
实现),以确保请求解锁的资源与已锁定的资源相同。validityEndTime
锁将在其中自动释放的时间(自 EPOCH 以来以毫秒为单位)(如果已定义 ttl)。
令牌生成器
由于 Locker
需要生成一个唯一的令牌来锁定 resource
,因此定义了一个 TokenGenerator
接口,并提供了 2 个实现
RandomTokenGenerator
将提供一个随机令牌。FixedTokenGenerator
将始终提供在构造函数中传递的令牌。
示例
use RemiSan\Lock\TokenGenerator\RandomTokenGenerator; $tokenGenerator = new RandomTokenGenerator(); echo $tokenGenerator->generateToken(); // 'QcWY1WFoRTC68vTNIkTs5cuLmw9YuY9rwS6IsY0xjzA='
use RemiSan\Lock\TokenGenerator\FixedTokenGenerator; $tokenGenerator = new FixedTokenGenerator('my_token'); echo $tokenGenerator->generateToken(); // 'my_token'
法定人数
Quorum
用于确定是否足够的 LockStores
已将锁写入以将其视为真正锁定。
提供了两种实现
MajorityQuorum
如果超过一半的存储已写入锁,则认为法定人数已满足。UnanimousQuorum
如果所有存储都已写入锁,则认为法定人数已满足。
法定人数仅在处理多个存储时使用。
用法
创建
您可以选择使用单存储实现
use RemiSan\Lock\LockStore\RedisLockStore; use RemiSan\Lock\Locker\SingleStoreLocker; use RemiSan\Lock\TokenGenerator\RandomTokenGenerator; use Symfony\Component\Stopwatch\Stopwatch; $connection = new \Redis(); $server->connect('127.0.0.1', 6379, 0.1); $tokenGenerator = new RandomTokenGenerator(); $stopwatch = new Stopwatch(); $redLock = new SingleStoreLocker( new RedisLockStore($connection), $tokenGenerator, $stopwatch );
或使用多存储实现
use RemiSan\Lock\LockStore\RedisLockStore; use RemiSan\Lock\Locker\MultipleStoreLocker; use RemiSan\Lock\Quorum\MajorityQuorum; use RemiSan\Lock\TokenGenerator\RandomTokenGenerator; use Symfony\Component\Stopwatch\Stopwatch; $connection1 = new \Redis(); $server->connect('127.0.0.1', 6379, 0.1); $connection2 = new \Redis(); $server->connect('127.0.0.1', 6380, 0.1); $tokenGenerator = new RandomTokenGenerator(); $quorum = new MajorityQuorum(); $stopwatch = new Stopwatch(); $redLock = new MultipleStoreLocker( [ new RedisLockStore($connection1), new RedisLockStore($connection2) ], $tokenGenerator, $quorum, $stopwatch );
获取锁
您可以通过提供资源名称、ttl
、重试次数以及重试前等待的时间(以毫秒为单位)来锁定资源。
$lock = $locker->lock('my_resource_name', 1000, 3, 100);
此示例将尝试锁定名为 my_resource_name
的资源 1 秒(1000ms),并在第一次失败时重试 3 次(如果全部失败则为 4 次),每次尝试之间等待 100ms。
如果获取锁成功,它将返回一个描述它的 Lock
对象。
如果获取锁失败,它将抛出 RemiSan\Lock\Exceptions\LockingException
。
对于多存储:只有当能够获取锁的实例数量满足法定人数时,才会获取锁(quorum
的计算是根据传递给 MultipleInstanceLocker
的 Quorum
的实现进行的)。
检查是否存在锁
您可以询问 Locker
资源是否仍然被锁定。
$isLocked = $locker->isLocked('my_resource_name');
如果资源仍然被锁定(锁已被获取且 ttl 未过期),它将返回 true
,否则返回 false
。
对于多存储:如果至少有一个连接的实例具有锁,它将考虑拥有锁。
释放锁
要释放锁,您必须将其提供给 Locker
。
$locker->unlock($lock);
如果锁仍然处于活动状态,则会释放它。如果操作失败但锁已不再活动,则不会引发任何错误。
如果在释放锁时失败且锁仍然处于活动状态,将抛出 RemiSan\Lock\Exceptions\UnlockingException
。
对于多实例存储:如果至少一个连接的实例在保持锁的同时释放锁失败,将抛出异常。
Redis 锁存储
基于Redlock-rb,由Salvatore Sanfilippo和ronnylt/redlock-php提供。
此库实现了基于Redis的分布式锁管理器算法,该算法在这篇Redis文章中描述。
此库提供了一个实现RedLock
机制的RedisLockStore
。
免责声明:正如原始的antirez
版本中所述,此代码实现了一个目前还处于提案阶段的算法,尚未经过正式分析。在使用生产环境之前,请务必了解其工作原理。
其他锁存储
这将在某个时候实现,但目前还没有。