应用篇:1.分布式锁
PHP DIY系列–一起手写一个api框架
含义
为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。
分析
- 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
- 高可用的获取锁与释放锁
- 高性能的获取锁与释放锁
- 具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
- 具备锁失效机制,防止死锁
- 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
实现方式
常见的有:
- 基于Redis
- 基于mysql
- 基于Zookeeper
具体实现
考虑到我们使用的PHP语言,简单结合Redis来实现一下分布式锁。
我们来画个简单的原理图:
原理十分简单,那么我们如何实现呢?
这里我们用到两个知识点:
- Redis的setnx方法
- php的register
function processLock($Redis, $key, $ttl = 5)
{
$ret = $Redis->setnx($key, 1);
if ($ret) {
$Redis->expire($key, $ttl);
register_shutdown_function(function () use ($Redis, $key){
$Redis->del($key);
});
}
return $ret;
}
demo里的$Redis是一个Redis实例,我们在前面已经实现过,不多说明。
加锁
我们使用的setnx命令,senx表示“SET if Not eXists”,如果key不存在,则set,如果存在,则不set
Redis> SETNX mykey "Hello"
(integer) 1
Redis> SETNX mykey "World"
(integer) 0
Redis> GET mykey
"Hello"
解锁
使用的是del,即删除这个key。这里结合了 register_shutdown_function — 注册一个会在php中止时执行的函数,设置了之后我们就可以不必手动去解锁
锁超时
这里给锁加了一个expire过期时间5秒,目的是防止使用这个方法之后的执行了“神奇”代码抛出了语法错误,导致register_shutdown_function里的代码没有执行,虽然请求结束,但是加锁后,没有解锁,影响了后续请求。
问题
- 加入setnx之后expire之前程序异常了怎么办?
应用篇:1.分布式锁
https://blog.puresai.com/2020/02/22/phpframe13/