PHP中如何通过redis示例详细实现分布式锁机制?

更新于
2026-09-27 12:36:37
1阅读来源:SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1868个文字,预计阅读时间需要8分钟。

PHP中如何通过redis示例详细实现分布式锁机制?

目录- 什么是分布式锁- 分布式锁实现原理- PHP实现代码- 最近在做一个领功能时,发现并解决了一个潜在的问题

在实现分布式锁时,使用分布式锁可以有效解决多节点并发执行导致的数据一致性问题。下面是关于分布式锁的简要介绍和实现方法:

什么是分布式锁:分布式锁是一种确保在分布式系统中,同一时间只有一个节点可以访问特定资源的机制。

分布式锁实现原理:分布式锁通常依赖于外部存储(如Redis)来实现锁的同步和状态保持。原理是通过在共享存储中创建一个锁标识,并在锁被占用时进行阻塞等待。

PHP实现代码:php

function redisLock($lockKey) { $locked=false; do { // 尝试设置锁,设置成功则获取锁 if (redis()->set($lockKey, time(), ['nx', 'ex'=> 30])) { $locked=true; } } while (!$locked); return $locked;}?>

最近在做一个领功能时,发现并解决了一个潜在的问题:在并发环境下,可能会出现多个节点同时获取到锁的情况,导致重复执行领功能。通过使用分布式锁,可以有效避免这个问题。在实现分布式锁的过程中,我们使用了Redis作为锁的存储,并通过设置锁的过期时间来确保锁在一段时间后自动释放。

目录
  • 什么是分布式锁
  • 实现原理
  • php实现代码

最近在做一个领券功能的时候,发现在一定并发下会出现重复领券的问题。使用度娘一顿搜索操作之后,发现可以使用分布式锁来解决这个问题。

什么是分布式锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。

实现原理

实现分布式锁的原理很简单,就是需要有一把锁,多个服务同时去获取锁,但是只有一个服务能获取到锁。获取到锁的服务就可以执行自己的业务,没有获取到锁的其他服务需要等待获取到锁的服务业务执行完成后释放锁,然后再次尝试获取锁。

实现分布式的方案有很多种。如下

PHP中如何通过redis示例详细实现分布式锁机制?

  • 基于数据库实现分布式锁,比如mysql
  • 基于缓存实现分布式锁,比如redis
  • 基于Zookeeper实现分布式锁

这里我们使用redis来实现分布式锁,在执行业务之前先获取一个key,如果key存在就说明已经有其他服务获得锁,这个时候需要等待或者返回系统繁忙。如果key不存在,说明没有其他服务获取锁,把这个key保存到redis,然后执行业务,等待业务执行完就从redis中删除这个key。

php实现代码

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value){ $this->redis->set($key,$value); } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $redisLock->setLock($key,$value); //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

使用ab进行测试

加锁
加锁
加锁
加锁
加锁
加锁
加锁
加锁
执行业务
解锁
解锁
执行业务
解锁
执行业务
解锁
执行业务
解锁
解锁
执行业务
解锁
加锁
执行业务
解锁
加锁
执行业务
解锁

从测试结果来看,发现有多个执行业务,并没有完全锁住。这个是因为我们用的是redis的set命令。set 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。这样会导致很多服务都能加锁成功,而我们想要的是只有一个服务能加锁成功。

要解决这个问题,需要了解redis的另一个命令setnx。setnx 命令在指定的 key 不存在时,为 key 设置指定的值。

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value){ return $this->redis->setnx($key,$value); } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $setLock = $redisLock->setLock($key,$value); if(!$setLock) { //加锁失败 return false; } //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

再次使用ab进行测试

加锁
加锁
加锁
加锁
加锁
加锁
加锁
加锁失败
加锁失败
加锁失败
加锁失败
加锁失败
已锁
已锁
已锁
执行业务
解锁

从测试结果来看,在未加锁的状态下,有多个服务同时获取加锁,但是只有一个加锁成功, 其他的都是返回加锁失败,再后面的服务更是直接返回已锁。由此可见,加锁成功。

那么到此就结束了吗?其实并不是的。假如在已加锁的情况执行业务,在业务过程中因为一些原因出现异常导致退出而没有进行解锁,那么将造成死锁,后面的所有服务都无法再次获取锁。为了解决这个问题,我们需要对锁设置一个过期的时间,防止死锁的发生。

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value,$second){ $setnx = $this->redis->setnx($key,$value); if(!$setnx) { return $setnx; } $expire = $this->redis->expire($key,$second); if(!$expire) { $this->redis->del($key); } return $expire; } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $second = 5; $setLock = $redisLock->setLock($key,$value,$second); if(!$setLock) { //加锁失败 return false; } //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

以上就是PHP使用redis实现分布式锁的示例详解的详细内容,更多关于PHP redis分布式锁的资料请关注自由互联其它相关文章!

标签:示例详解

本文共计1868个文字,预计阅读时间需要8分钟。

PHP中如何通过redis示例详细实现分布式锁机制?

目录- 什么是分布式锁- 分布式锁实现原理- PHP实现代码- 最近在做一个领功能时,发现并解决了一个潜在的问题

在实现分布式锁时,使用分布式锁可以有效解决多节点并发执行导致的数据一致性问题。下面是关于分布式锁的简要介绍和实现方法:

什么是分布式锁:分布式锁是一种确保在分布式系统中,同一时间只有一个节点可以访问特定资源的机制。

分布式锁实现原理:分布式锁通常依赖于外部存储(如Redis)来实现锁的同步和状态保持。原理是通过在共享存储中创建一个锁标识,并在锁被占用时进行阻塞等待。

PHP实现代码:php

function redisLock($lockKey) { $locked=false; do { // 尝试设置锁,设置成功则获取锁 if (redis()->set($lockKey, time(), ['nx', 'ex'=> 30])) { $locked=true; } } while (!$locked); return $locked;}?>

最近在做一个领功能时,发现并解决了一个潜在的问题:在并发环境下,可能会出现多个节点同时获取到锁的情况,导致重复执行领功能。通过使用分布式锁,可以有效避免这个问题。在实现分布式锁的过程中,我们使用了Redis作为锁的存储,并通过设置锁的过期时间来确保锁在一段时间后自动释放。

目录
  • 什么是分布式锁
  • 实现原理
  • php实现代码

最近在做一个领券功能的时候,发现在一定并发下会出现重复领券的问题。使用度娘一顿搜索操作之后,发现可以使用分布式锁来解决这个问题。

什么是分布式锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。

实现原理

实现分布式锁的原理很简单,就是需要有一把锁,多个服务同时去获取锁,但是只有一个服务能获取到锁。获取到锁的服务就可以执行自己的业务,没有获取到锁的其他服务需要等待获取到锁的服务业务执行完成后释放锁,然后再次尝试获取锁。

实现分布式的方案有很多种。如下

PHP中如何通过redis示例详细实现分布式锁机制?

  • 基于数据库实现分布式锁,比如mysql
  • 基于缓存实现分布式锁,比如redis
  • 基于Zookeeper实现分布式锁

这里我们使用redis来实现分布式锁,在执行业务之前先获取一个key,如果key存在就说明已经有其他服务获得锁,这个时候需要等待或者返回系统繁忙。如果key不存在,说明没有其他服务获取锁,把这个key保存到redis,然后执行业务,等待业务执行完就从redis中删除这个key。

php实现代码

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value){ $this->redis->set($key,$value); } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $redisLock->setLock($key,$value); //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

使用ab进行测试

加锁
加锁
加锁
加锁
加锁
加锁
加锁
加锁
执行业务
解锁
解锁
执行业务
解锁
执行业务
解锁
执行业务
解锁
解锁
执行业务
解锁
加锁
执行业务
解锁
加锁
执行业务
解锁

从测试结果来看,发现有多个执行业务,并没有完全锁住。这个是因为我们用的是redis的set命令。set 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。这样会导致很多服务都能加锁成功,而我们想要的是只有一个服务能加锁成功。

要解决这个问题,需要了解redis的另一个命令setnx。setnx 命令在指定的 key 不存在时,为 key 设置指定的值。

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value){ return $this->redis->setnx($key,$value); } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $setLock = $redisLock->setLock($key,$value); if(!$setLock) { //加锁失败 return false; } //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

再次使用ab进行测试

加锁
加锁
加锁
加锁
加锁
加锁
加锁
加锁失败
加锁失败
加锁失败
加锁失败
加锁失败
已锁
已锁
已锁
执行业务
解锁

从测试结果来看,在未加锁的状态下,有多个服务同时获取加锁,但是只有一个加锁成功, 其他的都是返回加锁失败,再后面的服务更是直接返回已锁。由此可见,加锁成功。

那么到此就结束了吗?其实并不是的。假如在已加锁的情况执行业务,在业务过程中因为一些原因出现异常导致退出而没有进行解锁,那么将造成死锁,后面的所有服务都无法再次获取锁。为了解决这个问题,我们需要对锁设置一个过期的时间,防止死锁的发生。

<?php class RedisLock { protected $redis; public function __construct(){ $redis = new Redis(); $redis->connect('127.0.0.1',6379); $this->redis = $redis; } public function getLock($key){ $value = $this->redis->get($key); return $value; } public function setLock($key,$value,$second){ $setnx = $this->redis->setnx($key,$value); if(!$setnx) { return $setnx; } $expire = $this->redis->expire($key,$second); if(!$expire) { $this->redis->del($key); } return $expire; } public function delLock($key){ $lineNumber = $thid->redis->del($key); return $lineNumber; } } $key = 'your_lock_key'; $value = time(); $redisLock = new RedisLock(); $isLock = $redisLock->get($key); if($isLock) { //已有锁,直接返回,不往下执行了 return false; } //没有锁,加锁 $second = 5; $setLock = $redisLock->setLock($key,$value,$second); if(!$setLock) { //加锁失败 return false; } //todo 执行业务逻辑 sleep(5); // 解锁 $redisLock->delLock($key);

以上就是PHP使用redis实现分布式锁的示例详解的详细内容,更多关于PHP redis分布式锁的资料请关注自由互联其它相关文章!

标签:示例详解