Laravel Redis Lua 分布式锁,解决高并发超卖

PHP 投稿 89100 0 评论

Laravel Redis Lua 分布式锁,解决高并发超卖

什么是分布式锁?当不同的进程必须以互斥地方式访问同一个共享资源时,就要用到分布式锁。当然,我更建议在工程实践时合理设计方案,避免用到锁,除非无法避免。网上也有一些比较简单的设计方案,其可靠性往往得不到很好的保证。

分布式锁的基本要求

一个最小化、可有效使用的分布式锁至少需满足以下三个属性:

  1. 安全性:互斥。对于同一资源,在任何时刻,只有一个客户端可以持有锁。

  2. 活跃性 A:死锁释放。当持有锁的客户端发生崩溃等异常而不能释放锁时,锁最终也能被其它客户端获取到。

  3. 活跃性 B:容错。只要大多数(半数以上)Redis 节点处于启动状态,客户端就可以获取和释放锁。

不能满足以上三个属性,则不是一个合格的分布式锁方案,其可靠性不足以在生产环境使用。在选择分布式锁方案时要牢记这三点。


redlock地址:https://github.com/topics/redlock

首先使用 composer 导入对应包:

composer require rtckit/react-redlock

第一种实现方式:

public function buy()
{
    /** @var Factory $factory 初始化一个Redis实例*/
    $factory = new \Clue\React\Redis\Factory();
    $client  = $factory->createLazyClient('127.0.0.1');
    /** @var Custodian $custodian 初始化一个锁监听器*/
    $custodian = new \RTCKit\React\Redlock\Custodian($client);
    $custodian->acquire('resource', 60, 'r4nd0m_token')
        ->then(function (?Lock $lock) use ($custodian) {
            if (is_null($lock)) {
                // 获取锁失败
            } else {
                // 添加一个10s生命周期的锁
                // TODO 处理业务逻辑
                // 释放锁
                $custodian->release($lock);
            }
        });
}

该方式使用 Redis 的 set + nx 命令实现原子性加锁,然后给当前加的锁设置一个随机的字符串,用来处理释放当前锁时,不能去释放他人的锁。调用了一个 lua 脚本 release 释放锁。保证锁的释放是一个原子性的。

第二种实现方式:

public function buy()
{
    /** @var Factory $factory 初始化一个Redis实例*/
    $factory = new \Clue\React\Redis\Factory();
    $client  = $factory->createLazyClient('127.0.0.1');
    /** @var Custodian $custodian 初始化一个锁监听器*/
    $custodian = new \RTCKit\React\Redlock\Custodian($client);
    $custodian->spin(100, 0.5, 'resource', 10, 'r4nd0m_token')
        ->then(function (?Lock $lock) use ($custodian) : void {
            if (is_null($lock)) {
                // 将进行100次的场次,每一次间隔0.5秒去获取锁,如果没有获取到锁。则放弃加锁请求。
            } else {
                // 添加一个10s生命周期的锁
                // TODO 处理业务逻辑
                // 释放锁
                $custodian->release($lock);
            }
        });
}

该方式加了一个自旋锁。在一定时间内一直获取锁,如果没有获取到则放弃当前的请求。

编程笔记 » Laravel Redis Lua 分布式锁,解决高并发超卖

赞同 (69) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽