perl - Perl NFS 锁的奇怪行为
问题描述
我在 Perl v5.16 中遇到来自 File::NFSLock 的奇怪行为。我使用过时的锁定超时选项为 5 分钟。假设我有三个进程。其中一个在释放锁之前花费了 5 分钟以上,并且进程 2 获得了锁。然而,即使进程 2 的锁定时间不到 5 分钟,第三个进程即将到来并删除锁定文件,导致第二个进程在删除自身持有的 NFSLock 时失败。
我的理论说进程 3 错误地读取了锁的最后修改时间,因为它是由进程 1 而不是进程 2 写入的。我正在对挂载在 NFS 上的分区写入 nfs 锁。
有人对 perl NFSLock 有想法或面临类似问题吗?请参考以下快照
my $lock = new File::NFSLock {file => $file,
lock_type => LOCK_EX,
blocking_timeout => 50, # 50 sec
stale_lock_timeout => 5 * 60};# 5 min
$DB::single = 1;
if ($lock) {
$lock->unlock()
}
如果我在进程 1 的调试器点阻塞超过 5 分钟,我正在观察这种行为
解决方案
通过查看
https://metacpan.org/pod/File::NFSLock
上的代码,
我看到 Lock 仅由系统中的物理文件实现。
我几乎在每个项目中都使用相同的进程锁定逻辑。
使用 Process Lock 至关重要的是不要设置stale_lock_timeout
得太紧。
或者它会发生“竞争条件”,因为它也在代码注释中提到。
正如您所提到的,这 3 个进程开始竞争同一个锁,因为作业需要> 5 分钟并且您将其设置tale_lock_timeout
为 5 分钟。
如果您有像crond
服务这样的固定时间提供者,这将每 5 分钟启动一个进程。每个进程都将 Lock 视为已过时,因为尽管该进程需要超过5 分钟,但已经过了 5 分钟
描述一个可能的场景:
一些 DB 作业需要 4 分钟才能完成,但在拥塞的系统上可能需要 7 分钟或更长时间。
现在,如果crond
服务每 5 分钟启动一个进程,
在 0 分钟时,第一个进程process1
将发现作业是新的,并设置锁定并启动作业,这将需要 7 分钟。
现在在 5 分钟时,crond
服务将启动process2
,它会找到 Lock ,process1
但决定它已经过时,因为自 Lock 创建以来已经 5 分钟,它将被视为stale。所以process2
释放锁并为自己重新获取它。
稍后7 分钟 process1
已经完成了 Job 并且没有检查它是否仍然是他的 Lock 它释放 Lockprocess2
并完成。
现在在 10 分钟 process3
启动并没有找到任何锁,因为锁process2
已经被释放process1
并设置了自己的锁。
这种情况实际上是有问题的,因为它会导致流程积累和工作量积累以及不可预测的结果。
解决此问题的建议是:
- 设置
stale_lock_timeout
为远大于工作所需的量(如 10 分钟或 15 分钟)。但stale_lock_timeout
比执行时间安排要大。
- 将执行计划设置得更宽敞,以便为每个进程提供足够的时间来完成其任务(每 10 分钟或每 15 分钟)
- 考虑将
process1
,process2
和 的作业集成process3
到一个仅process_master
在前一次完成后启动每个进程的作业中。
推荐阅读
- python - 使用 For 循环显示数组中特定数量的随机项
- python - 循环处理免责声明
- python - 根据 osmnx 中的属性为节点着色
- python - 如何识别熊猫中的静态值?
- html - 如何在 Html / Bootstrap 中控制容器的大小?
- oracle - Jenkins Oracle 身份验证
- logic - 将引理应用于合取分支而不在 coq 中拆分
- dataframe - 在 DataFrame 中操作数据:如何计算列的平方
- javascript - 基于映射数组字段的 React Native 条件样式
- ios - 带有 UIViewRepresantable 的 UITableView 的某些单元格位置错误