php+redis+lua实现分布式锁(转载)
以下是我在工作中用到的类,redis加锁两种方式,解锁为了保证原子性所以只用lua+redis的方式
缺陷:虽然死锁问题解决了,但业务执行时间超过锁有效期还是存在多客户端加锁问题。
不过,这个类已经满足了我现在的业务需求
更优的解决方案可以参考以下两篇文章:
https://redis.io/topics/distlock (Redlock的算法描述)
https://mp.weixin.qq.com/s/1bPLk_VZhZ0QYNZS8LkviA
代码实现:
class RedisLock
{
/**
* @var 当前锁标识,用于解锁
*/
private $_lockFlag;
private $_redis;
public function __construct($host = '127.0.0.1', $port = '6379', $passwd = '')
{
$this->_redis = new Redis();
$this->_redis->connect($host, $port);
if ($passwd) {
$this->_redis->auth($passwd);
}
}
public function lock($key, $expire = 5)
{
$now= time();
$expireTime = $expire + $now;
if ($this->_redis->setnx($key, $expireTime)) {
$this->_lockFlag = $expireTime;
return true;
}
// 获取上一个锁的到期时间
$currentLockTime = $this->_redis->get($key);
if ($currentLockTime < $now) {
/* 用于解决
C0超时了,还持有锁,加入C1/C2/...同时请求进入了方法里面
C1/C2都执行了getset方法(由于getset方法的原子性,
所以两个请求返回的值必定不相等保证了C1/C2只有一个获取了锁) */
$oldLockTime = $this->_redis->getset($key, $expireTime);
if ($currentLockTime == $oldLockTime) {
$this->_lockFlag = $expireTime;
return true;
}
}
return false;
}
public function lockByLua($key, $expire = 5)
{
$script = <<<EOF
local key = KEYS[1]
local value = ARGV[1]
local ttl = ARGV[2]
if (redis.call('setnx', key, value) == 1) then
return redis.call('expire', key, ttl)
elseif (redis.call('ttl', key) == -1) then
return redis.call('expire', key, ttl)
end
return 0
EOF;
$this->_lockFlag = md5(microtime(true));
return $this->_eval($script, [$key, $this->_lockFlag, $expire]);
}
public function unlock($key)
{
$script = <<<EOF
local key = KEYS[1]
local value = ARGV[1]
if (redis.call('exists', key) == 1 and redis.call('get', key) == value)
then
return redis.call('del', key)
end
return 0
EOF;
if ($this->_lockFlag) {
return $this->_eval($script, [$key, $this->_lockFlag]);
}
}
private function _eval($script, array $params, $keyNum = 1)
{
$hash = $this->_redis->script('load', $script);
return $this->_redis->evalSha($hash, $params, $keyNum);
}
}
$redisLock = new RedisLock();
$key = 'lock';
if ($redisLock->lockByLua($key)) {
// to do...
$redisLock->unlock($key);
}
php+redis+lua实现分布式锁(转载)的更多相关文章
- Redis系列(二)--分布式锁、分布式ID简单实现及思路
分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...
- 如何用redis正确实现分布式锁?
先把结论抛出来:redis无法正确实现分布式锁!即使是redis单节点也不行!redis的所谓分布式锁无法用在对锁要求严格的场景下,比如:同一个时间点只能有一个客户端获取锁. 首先来看下单节点下一般r ...
- redis系列:分布式锁
redis系列:分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- Redis如何实现分布式锁
今天我们来聊一聊分布式锁的那些事. 相信大家对锁已经不陌生了,我们在多线程环境中,如果需要对同一个资源进行操作,为了避免数据不一致,我们需要在操作共享资源之前进行加锁操作.在计算机科学中,锁(lock ...
- 基于redis实现的分布式锁
基于redis实现的分布式锁 我们知道,在多线程环境中,锁是实现共享资源互斥访问的重要机制,以保证任何时刻只有一个线程在访问共享资源.锁的基本原理是:用一个状态值表示锁,对锁的占用和释放通过状态值来标 ...
- 一个Redis实现的分布式锁
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.conne ...
- 基于Redis的简单分布式锁的原理
参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...
- redis客户端、分布式锁及数据一致性
Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...
- 在redis上实现分布式锁
/** *在redis上实现分布式锁 */ class RedisLock { private $redisString; private $lockedNames = []; public func ...
随机推荐
- http keep-alive 的一些理解
在日常的工作中涉及到了关于检测用户是否在线的功能需求,在方案设计过程中考虑过使用http-keepalive的方式,由于我们获取到的keepalive是经过nginx转发的keep-alive,所以最 ...
- 【Web前端HTML5&CSS3】11-定位
笔记来源:尚硅谷Web前端HTML5&CSS3初学者零基础入门全套完整版 目录 定位的简介 1. 相对定位 偏移量(offset) 相对定位的特点 2. 绝对定位 绝对定位的特点 包含块(co ...
- 回顾Servlet
1.新建一个Maven工程当做父工程!pom依赖! <!-- 依赖 --> <dependencies> <dependency> <groupId>j ...
- Python+Selenium - iframe定位
元素在iframe中.在html当中,内嵌了另一个html (iframe) 分辨元素是否在iframe当中 在代码当中,从当前的html切换到iframe当中的html,然后在元素定位 切换方式:d ...
- TheSuperego 实验六 团队作业3:项目需求分析与原型设计
项目 内容 课程班级博客链接 班级博客 这个作业要求链接 作业要求 团队名称 TheSuperego 团队成员分工描述 杨丽霞:组织QQ会议,合理明确组内分工,推进任务,实施关于我们原型设计陈来弟:负 ...
- TensorFlow Frontend前端
TensorFlow Frontend前端 TensorFlow前端有助于将TensorFlow模型导入TVM. Supported versions: 1.12 and below Tested m ...
- 可视化反投射:坍塌尺寸的概率恢复:ICCV9论文解读
可视化反投射:坍塌尺寸的概率恢复:ICCV9论文解读 Visual Deprojection: Probabilistic Recovery of Collapsed Dimensions 论文链接: ...
- 自定义 DataLoader
自定义 DataLoader 如 数据输入 一文所介绍,OneFlow 支持两种数据加载方式:直接使用 NumPy 数据或者使用 DataLoader 及其相关算子. 在大型工业场景下,数据加载容易成 ...
- Python神经网络集成技术Guide指南
Python神经网络集成技术Guide指南 本指南将介绍如何加载一个神经网络集成系统并从Python运行推断. 提示 所有框架的神经网络集成系统运行时接口都是相同的,因此本指南适用于所有受支持框架(包 ...
- 5G和AI机器人平台为工业4.0和无人机提供服务
5G和AI机器人平台为工业4.0和无人机提供服务 Qualcomm 5G and AI robotics platform delivers for Industry 4.0 and drones 高 ...