天天看点

php框架 Hyperf 与redis分布式锁 这样写

1、什么是分布式锁:

分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程。

2、分布式锁应该具备哪些条件:

  • 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  • 高可用的获取锁与释放锁
  • 高性能的获取锁与释放锁
  • 具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
  • 具备锁失效机制,即自动解锁,防止死锁
  • 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

3、分布式锁的实现方式:

  • 基于数据库实现分布式锁
  • 基于Zookeeper实现分布式锁
  • 基于reids实现分布式锁

下面是基于Redis实现的分布式锁,代码实例直接用就好了!

<?php

namespace App\Support;

use Hyperf\Redis\Redis;

class RedisDistributedLock
{
    /**
     * @var Redis
     */
    private Redis $redis;

    /**
     * 锁的名称
     * @var string
     */
    private string $lockKey;

    /**
     * 锁的超时时间,单位:毫秒
     * @var int
     */
    private int $lockTimeout;

    /**
     * 加锁成功后的锁值,用于释放锁
     * @var string
     */
    private string $lockValue;

    /**
     * @param Redis $redis
     * @param string $lockKey
     * @param int $lockTimeout
     */
    public function __construct(Redis $redis, string $lockKey, int $lockTimeout)
    {
        $this->redis = $redis;
        $this->lockKey = $lockKey;
        $this->lockTimeout = $lockTimeout;
    }

    /**
     * 获取锁
     * @return bool
     */
    public function lock(): bool
    {
        // 获取锁的值
        $this->lockValue = uniqid();
        // 尝试获取锁
        $isLocked = $this->redis->set($this->lockKey, $this->lockValue, ['NX', 'PX' => $this->lockTimeout]);
        return (bool)$isLocked;
    }

    /**
     * 释放锁
     * @return void
     */
    public function release(): void
    {
        $script = <<<LUA
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end
LUA;
        $this->redis->eval($script, [$this->lockKey, $this->lockValue], 1);
    }
}
           

如何使用

use App\Model\DistributedLock;

$redis = new Redis(...);
$lock = new DistributedLock($redis, 'lock_key', 10000);
if ($lock->lock()) {
    try {
        // 执行临界区代码
    } finally {
        $lock->release();
    }
} else {
    // 获取锁失败
}
           

部分参考自:Redis进阶应用:Redis+Lua脚本实现复合操作_cengnai6732的博客-CSDN博客