![可以互相调用的脚本的共享锁定](https://linux22.com/image/208965/%E5%8F%AF%E4%BB%A5%E4%BA%92%E7%9B%B8%E8%B0%83%E7%94%A8%E7%9A%84%E8%84%9A%E6%9C%AC%E7%9A%84%E5%85%B1%E4%BA%AB%E9%94%81%E5%AE%9A.png)
这是一个不寻常的问题,可能是不良设计的结果。如果有人能提出更好的建议,我很乐意听到。但现在我想“按原样”解决它。
有一堆交互脚本。为了问题的目的并不重要,为了完整起见,这些脚本在物理备用和快照备用之间切换Oracle数据库备用节点,创建快照数据库并为我们的报告团队添加一些拨款,在此过程中释放过时的存档日志。
有:
delete_archivelogs.sh
switch_to_physical_standby.sh
delete_archivelogs.sh
,最后也会调用switch_to_snapshot_standby.sh
sync_standby.sh
,它调用switch_to_physical_standby.sh
,等待待机状态赶上,然后调用switch_to_snapshot_standby.sh
最后一个sync_standby.sh
通常从 cron 作业运行,但如果 DBA 决定这样做,每个脚本也应该可以随意运行。
每个脚本都有一个基于锁定文件的保护(通过集群)防止运行两次。然而,很明显,这些脚本需要有一个共享的公共锁定,例如,在运行时不可能switch_to_snapshot_standby.sh
(单独)启动sync_standby.sh
,因此 DBA 不会在其他脚本正在工作时意外运行一个脚本。
通常我只是在所有脚本中配置相同的锁定文件。在这种情况下这是不可能的,因为如果sync_standby.sh
获取锁,被调用的脚本将不会运行。
在这种情况下,哪种共享锁定的最佳方法是?实现“命令行”开关来跳过锁定代码并在父脚本的调用中使用它是否可行?
答案1
如果您的脚本都不需要或不需要命令行选项,您可以使用命令行选项来指示“从属”脚本是否要使用该flock
机制。
因此,在您的示例中,sync_standby.sh
脚本将使用switch_to_snapshot_standby.sh
参数调用 (eg) subordinate
,例如
./switch_to_snapshot_standby.sh subordinate
然后,该switch_to_snapshot_standby.sh
脚本将检查是否使用参数调用它,并flock
在这种情况下绕过代码:
if [[ "$1" != "subordinate" ]]
then
flock # with your arguments
fi
如果您的脚本使用命令行参数,您也可以使用该机制,但显然需要对它们进行排序以查看是否subordinate
提供了参数。
答案2
每个脚本都应该检查专用环境变量是否存在(实际上:空与非空)。为变量选择一个未使用的名称。如果变量存在,那么脚本应该假设它已经持有锁(继承)。
如果变量不存在,脚本应尝试获取锁。如果成功,它应该确保其他脚本将在其环境中获取该变量。
概念证明
scrpt
:
#!/bin/bash
(
if [ -z "$HAVE_LOCK" ]; then
flock 9 || exit 1
export HAVE_LOCK=1
fi
date
sleep 1
[ "$RANDOM" -gt 3000 ] && ./scrpt
echo done
) 9>/tmp/my-lock
./scrpt
几乎同时在两个控制台中运行。其中一个将获得一把锁。它很有可能会一次又一次地调用自己,但没有一个后代会阻止。最终它会停止,而另一个会继续。
笔记:
bash
(不是sh
)只是因为我需要$RANDOM
。echo done
来自每个实例确保每个./scrpt
都是一个单独的进程。它不允许 Bash 隐式地exec ./scrpt
.我并不是说 Bash 会这样做;但我认为从技术上讲是可以的,那么这个例子就没有说服力。export
我立即选择了该变量,这样我就可以忘记它。HAVE_LOCK=1 ./scrpt
是一种在其环境中运行子级./scrpt
的方法HAVE_LOCK
,无需事先export
.该方法类似于这个另一个答案,但在我看来,它有一个优点:无论您的脚本已经使用哪些变量以及如何使用,检查额外的变量都不会干扰,它很简单,相关代码可能完全独立。添加对附加命令行选项的支持可能并不那么容易(取决于您的脚本是否已经使用命令行选项)。