Скрипт восстановления сервисов в случае их отказа

Задача

Одна из типовых ситуаций, которые возникают при эксплуатации web-сайтов - отказ сервиса HTTPD или СУБД. В данном примере, мы будем мониторить состояние двух наиболее часто применяемых сервисов: apache2 и mariadb. Отказ или аварийная остановка сервиса может произойти по ряду причин. Наиболее частые причины следующие:

  • переполнение оперативной памяти в сервере и, как следствие, отработка механизма OOM (Out of Memory) kill;
  • злонамеренная атака на сервис (bruteforce, SQL-injecting, DDoS и прочие виды атак);
  • переполнение дискового пространства.

Под понятием сервер подразумевается аппаратный сервер или виртуальная машина.

Естественно, это решение можно легко перенастоить и для других применений (сервисов).

Решение

Для того, чтобы автоматически восстановить работоспособность сервиса (web-сайта, как частный случай), создаем программу по имени /usr/local/bin/watcher:

#!/bin/bash
SRVL=(
mariadb
apache2
)
MIG=$(date +%y%m%d%H%M)
LOGF="/var/log/restart.log"

for SRV in ${SRVL[@]}; do
  if systemctl is-failed --quiet $SRV || ! systemctl is-active --quiet $SRV; then
    /usr/bin/systemctl start $SRV
    echo ${MIG}: ${SRV} restart >> $LOGF
  fi
done

Эта программа сможет автоматически восстановить работу сервисов, перечисленных в массиве ${SRVL} в случае отказа по двум первым из трех вышеприведенных причин.

Чтобы восстановить работоспособность сервисов, отказавших по причине переполнения дискового пространства - к сожалению, в большинстве случаев, требуется ручное вмешательство - надо смотреть, какие именно файлы можно удалить (как правило логи). В некоторых случаях - когда удалять уже нечего, поможет только расширение диска или подключение дополнительного диска.

Добавляем ее в crontab пользователя root для запуска каждые 2 минуты:

*/2 * * * * /usr/local/bin/watcher > /dev/null

Можно обойтись и без записи в планировщик - тогда надо создать файл сервиса и прописать в нем вызов прогаммы watcher.

Тестирование

Для того, чтобы смоделировать состояние переполнения оперативной памяти, смонтируем ФС tmpfs с размером, равным размеру RAM - в нашем примере 2Gb:

mkdir /mnt/tmpfs
mount -t tmpfs -o rw,nodev,nosuid,size=2G tmpfs  /mnt/tmpfs

Создаем файл контроля состояния сервиса oom_test:

#!/bin/bash
SRV=$1
if [[ -n $SRV ]]; then
  watch "if systemctl is-failed --quiet '${SRV}' || ! systemctl is-active --quiet '${SRV}'; then echo failed; else echo active; fi"
fi

Запускаем контроль, например, по сервису mariadb

./oom_test mariadb
Эмулируем заполнение RAM на 90%:

dd if=/dev/random of=/mnt/tmpfs/killer bs=1M count=1800

Видим на экране, где запущен oom_test, что сервис перешел в состояние failed.

Далее, искусственно уменьшим потребление ОЗУ, например до 900Кб:

dd if=/dev/random of=/mnt/tmpfs/killer bs=1M count=900

И в течении максимум двух минут, мы увидим, что сервис автоматически перешел в состояниеactive. Это свидетельствует о том, что наша программа правильно отработала и работоспособность web-сайта восстановилась в автоматическом режиме.

После окончания тестирования, не забываем очистить и отключить RAM-диск:

rm /mnt/tmpfs/killer; umount /mnt/tmpfs

Опубликовано: 15.02.2025