Скрипт запуска 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  

Поэтому мой вопрос ( s): Как процесс Apache «наследует» эти файловые дескрипторы? Почему такое же поведение не происходит с другими сценариями запуска (например, «запуск службы mysql»)? И есть ли способ избежать этого?

3
задан 2 May 2016 в 12:43

1 ответ

Так как никто не записал ответ (несмотря на щедрость), я собираюсь объясниться, как я наконец решил это.

комментарий muru (большое спасибо!) было правильным и принес мне на правильном пути: В Ubuntu 14.04 запуск Apache организован sysv init сценарий и быть сценарием оболочки, это наследовало все (переменные среды, открытые дескрипторы файлов, и т.д.), и апачский процесс, запущенный им, наследует все те также. Mysql, в свою очередь, управляет Выскочка, которая гарантирует чистую среду для запущенных сервисов. Это объясняет другое поведение для Mysql и Apache.

Вооруженный с тем знанием я знал лучше, что искать и нашел этот ответ на unix.stackexchange.com . Это предлагает закрыть дескриптор файла в подоболочке, которая называет сценарии, которые не должны наследовать его, в то время как хранение дескриптора открывается во внешней оболочке, чтобы удостовериться, что блокировка остается эффективной.

, К сожалению, это означает, что я должен был переместиться flock вызовы к в рамках сценария оболочки, иначе мой сценарий не будет знать который дескриптор файла закрыться. Таким образом, мой новый сценарий оболочки (который также взял некоторое вдохновение от это сообщение в блоге приблизительно 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>-"
3
ответ дан 2 May 2016 в 22:43
  • 1
    Я не могу найти или установить lvremove в своей системе Ubuntu. Спасибо, – OtagoHarbour 1 October 2017 в 07:27

Другие вопросы по тегам:

Похожие вопросы: