remi-san/lock

锁定库

v1.0.2 2021-02-21 15:02 UTC

This package is auto-updated.

Last update: 2024-09-21 22:12:25 UTC


README

Author Build Status Quality Score Software License Packagist Version Coverage Status SensioLabsInsight

描述

Lock 是一个旨在提供简单且可靠地锁定资源的库。

主要类

  • RemiSan\Lock\Locker 提供一个包含以下方法的接口

    • lock 用于锁定资源一段时间(ttl - 非必需),允许在成功之前重试一定次数。
    • isLocked 用于检查资源是否仍然被锁定。
    • unlock 用于解锁资源。
  • RemiSan\Lock\Lock 提供一个结构来存储关于锁的信息

    • resource 已被锁定的资源
    • tokenLocker 生成的令牌(使用 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 的计算是根据传递给 MultipleInstanceLockerQuorum 的实现进行的)。

检查是否存在锁

您可以询问 Locker 资源是否仍然被锁定。

$isLocked = $locker->isLocked('my_resource_name');

如果资源仍然被锁定(锁已被获取且 ttl 未过期),它将返回 true,否则返回 false

对于多存储:如果至少有一个连接的实例具有锁,它将考虑拥有锁。

释放锁

要释放锁,您必须将其提供给 Locker

$locker->unlock($lock);

如果锁仍然处于活动状态,则会释放它。如果操作失败但锁已不再活动,则不会引发任何错误。

如果在释放锁时失败且锁仍然处于活动状态,将抛出 RemiSan\Lock\Exceptions\UnlockingException

对于多实例存储:如果至少一个连接的实例在保持锁的同时释放锁失败,将抛出异常。

Redis 锁存储

基于Redlock-rb,由Salvatore Sanfilipporonnylt/redlock-php提供。

此库实现了基于Redis的分布式锁管理器算法,该算法在这篇Redis文章中描述。

此库提供了一个实现RedLock机制的RedisLockStore

免责声明:正如原始的antirez版本中所述,此代码实现了一个目前还处于提案阶段的算法,尚未经过正式分析。在使用生产环境之前,请务必了解其工作原理。

其他锁存储

这将在某个时候实现,但目前还没有。