Apache 启动脚本保持锁定文件打开

Apache 启动脚本保持锁定文件打开

我正在为备份任务编写一个 bash 脚本。除其他事项(文件系统冻结、数据库锁定、快照等)外,它还涉及关闭 Apache 并在备份后重新启动它。由于该脚本应作为 cronjob 运行,并且执行时间可能相差很大(特别是因为脚本等待“好时机”进行备份),我尝试使用 来保护它免于多次执行flock

但是,flock即使备份脚本退出后,仍会保持锁定。此行为与我的使用方式无关flock(使用脚本中打开的目录、文件或文件描述符)。

我把问题归结为 apache2 的重新启动,并可以在以下一行中看到它

flock -n /var/lock/startapache service apache2 start

请参阅以下交互式会话来说明该问题:

root@fermat:/home/ubuntu# service apache2 stop
 * Stopping web server apache2                                                                                                                  ... waiting .                                                                                                                          [ OK ]
root@fermat:/home/ubuntu# flock -n /var/lock/startapache service apache2 start || echo failed
 * Starting web server apache2                                                                                                          [ OK ] 
root@fermat:/home/ubuntu# flock -n /var/lock/startapache service apache2 start || echo failed
failed

这是因为启动的 Apache 脚本保持我的锁定文件描述符处于打开状态:

root@fermat:/home/ubuntu# lsof /var/lock/startapache 
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
apache2 23651 root    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23656 trac    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23674 trac    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23675 root    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23676 root    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23677 root    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23694 root    3u   REG   0,17        0 6673997 /run/lock/startapache
apache2 23696 root    3u   REG   0,17        0 6673997 /run/lock/startapache

一旦我关闭 Apache,锁就会再次被释放:

root@fermat:/home/ubuntu# service apache2 stop
 * Stopping web server apache2                                                                                                                  ... waiting                                                                                                                            [ OK ]
root@fermat:/home/ubuntu# flock -n /var/lock/startapache service apache2 start || echo failed
 * Starting web server apache2  

因此我的问题是:Apache 进程如何“继承”这些文件描述符?为什么其他启动脚本(例如“service mysql start”)不会发生相同的行为?有没有办法避免这种情况?

答案1

由于没有人写答案(尽管有赏金),我将自己解释一下我最终是如何解决这个问题的。

穆鲁的评论(非常感谢!)是正确的,并让我走上了正确的轨道:在 Ubuntu 14.04 中,Apache 启动由 sysv init 脚本管理,作为 shell 脚本,它继承了所有内容(环境变量、打开的文件描述符等),并且由它启动的 apache 进程也将继承所有这些。而 Mysql 由 Upstart 管理,这确保了启动服务的环境干净。这解释了 Mysql 和 Apache 的不同行为。

有了这些知识,我更清楚要寻找什么,并且找到了unix.stackexchange.com 上的这个答案。建议在调用不应继承它的脚本的子 shell 中关闭文件描述符,同时在外壳程序中保持描述符打开,以确保锁保持有效。

不幸的是,这意味着我必须将flock调用移到 shell 脚本中,否则我的脚本将不知道要关闭哪个文件描述符。所以我的新 shell 脚本(也从中汲取了一些灵感)这篇博客文章flock) 的结构如下:

#!/bin/bash

FLOCK_FILE="/var/lock/backup-lock"
FLOCK_FD=20

# Locking
eval "exec $FLOCK_FD>'$FLOCK_FILE'"
if ! flock -n $FLOCK_FD
then
  echo "FAILED! There is a backup script already running."
  exit 1
fi

(
  # Unlock in sub-shell, so daemons with bad startup scripts
  # (like Apache) don't inherit the look.
  # Note that the lock is still alive in general because it's
  # held by the outer shell.
  eval "exec $FLOCK_FD>-"


  # ... normal backup stuff from the original script ...

  # Among other stuff the mentioned vicious line:
  service apache2 start

  # ... normal backup stuff from the original script ...
)

# Unlock in outer shell because we're done.
eval "exec $FLOCK_FD>-"

相关内容