php实现redis分布式锁的核心是调用set命令并设置nx和ex参数,确保原子性获取锁。续期看门狗通常通过后台协程或独立进程监控锁的剩余时间,在过期前自动延长有效期以防止业务未执行完锁就失效。

如何原子性地获取带过期的分布式锁
使用SET key value NX EX timeout命令可以一次性完成检查是否存在、设置值和设定过期时间的操作,这是防止死锁的标准做法。在PHP中,推荐使用Predis或phpredis扩展直接发送该命令,避免先SETNX再EXPIRE导致的竞态条件。如果键已存在则返回false,否则返回true并持有锁。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'lock:order:123';
$value = uniqid(); // 唯一标识,用于释放时校验
$timeout = 10; // 锁持有超时时间(秒)
// 原子操作:仅当key不存在时设置,并设置过期时间
$isLocked = $redis->set($key, $value, ['nx', 'ex' => $timeout]);
if ($isLocked) {
try {
// 执行业务逻辑
echo "Lock acquired. Processing...\n";
sleep(5);
} finally {
// 释放锁:必须校验value,防止误删其他线程的锁
$script = 'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end';
$redis->eval($script, [$key, $value], 1);
echo "Lock released.\n";
}
} else {
echo "Failed to acquire lock.\n";
}
如何实现锁的自动续期看门狗
看门狗机制需要在获取锁成功后启动一个守护任务,定期检测锁是否仍由当前客户端持有,并在即将过期前重新设置过期时间。由于PHP通常是请求驱动模型,真正的看门狗需要借助Swoole等异步框架或在独立进程中运行。这里展示基于Swoole Timer的实现思路,它会在主业务结束前持续续期,一旦业务完成或异常退出,定时器停止,锁按原定时过期。

// 假设已在Swoole环境下运行
use Swoole\Timer;
function acquireLockWithWatchdog($redis, $key, $value, $ttl, $callback) {
$isLocked = $redis->set($key, $value, ['nx', 'ex' => $ttl]);
if (!$isLocked) {
return false;
}
$watchdogInterval = $ttl / 3; // 每1/3 TTL续期一次
$timerId = null;
// 定义续期回调
$renewFunc = function () use ($redis, $key, $value, $ttl, &$timerId) {
// 再次确认还是自己持有的锁(防止并发覆盖)
if ($redis->get($key) === $value) {
$redis->expire($key, $ttl);
} else {
// 锁已被他人获取,停止看门狗
Timer::clear($timerId);
}
};
// 启动定时器
$timerId = Timer::tick($watchdogInterval, $renewFunc);
try {
$callback(); // 执行业务
} finally {
// 业务结束,清除定时器
if ($timerId !== null) {
Timer::clear($timerId);
}
// 释放锁
$script = 'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end';
$redis->eval($script, [$key, $value], 1);
}
}
// 使用示例
acquireLockWithWatchdog($redis, 'lock:task', 'unique-id-123', 30, function() {
echo "Processing long task...\n";
sleep(25); // 模拟长耗时操作
});
如果业务执行时间超过锁的初始TTL会发生什么
如果不使用看门狗,当业务执行时间超过TTL时,锁会自动过期,此时其他客户端可能获取到同一把锁,导致并发安全问题。例如,若TTL设为10秒,而业务需15秒,第11秒时锁失效,第二个请求进入并获取锁,两个请求同时操作共享资源,造成数据错乱。因此,对于不确定耗时的业务,必须引入看门狗或动态调整TTL策略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











