У меня вчера ночью сайт упал. Утром пока встал, покушал, сел за компьютер, накопилось большое количество сообщений в личке от читателей, как в vk, так и в телеге. Даже не ожидал, что столько народу читают сайт, где уже давно не обновлялись статьи. Всем спасибо за беспокойство.
Ситуация получилась хрестоматийная, так что решил разобрать её и прокомментировать. Упала база данных Mariadb. Её прибил OOM Killer. По мере устаревания кэша, отваливались страницы. Рассказываю, почему это произошло.
Для меня сайт не является критически важным ресурсом, так что какого-то особого контроля за ним не веду. После очередного переезда на новый сервер, изменились его характеристики. Я быстро на глазок подогнал все конфиги под эти характеристики и оставил всё без точечной калибровки. Где-то месяц или два всё это нормально работало.
Вчера ночью кто-то немного нагрузил сайт. Существенно выросло число запросов, разросся access log веб сервера, стартовала куча процессов php-fpm, открылись подключения к базе. Параллельно сразу же выросла нагрузка от fail2ban, который анализирует лог файлы и от filebeat, который отправляет логи в ELK. В итоге OOM Killer одновременно прибил filebeat и mariadb. Причём filebeat поднялся сам, у него в systemd сервисе прописано Restart=always, а MariaDB нет, хотя там указано Restart=on-abort. По идее, с этой настройкой база тоже должна была подняться после остановки OOM Killer, но этого не случилось.
В итоге что я сделал:
1️⃣ Поправил конфиг MariaDB. Конкретно изменил параметры, которые снизили максимальное количество оперативной памяти, которую может забрать процесс:
key_buffer_sizeinnodb_buffer_pool_sizeinnodb_log_file_sizemax_connections
2️⃣ Поправил конфиг пула php-fpm. Заметил, что очень много запущено рабочих процессов, которые явно не используются все. Был 61 процесс, а после перезапуска понаблюдал и убедился, что для нормальной работы надо 10-15 штук всего. Процессы стартовали по потребности во время всплесков нагрузки, но долго потом висели в памяти, не закрывались. Добавил параметр pm.process_idle_timeout = 30, чтобы через 30 секунд неактивности рабочий процесс завершался. Также более строго ограничил максимальное количество рабочих процессов параметром pm.max_children, чтобы они не смогли занять слишком много памяти.
По сути просто сбалансировал потребление памяти между приложениями. Теперь надо нагрузить сайт одновременными тяжелыми запросами хотя бы с 10-15 разных IP адресов и посмотреть, сколько памяти скушают fail2ban и filebeat, чтобы ещё раз подкорректировать параметры. Желательно всё это замониторить, но в том же Zabbix нетривиальная задача настроить мониторинг, следящий за потреблением ресурсов отдельными динамическими процессами. Я знаю только одну систему мониторинга, которая это умеет из коробки - Newrelic.
Я не первый раз сталкиваюсь с ситуацией, когда сборщики и анализаторы логов непредсказуемо нагружают сервер. Тот же Fail2ban запросто его может положить сам при очень резком всплеске запросов. Так что это немного колхозное решение в лоб и нужно это понимать. С filebeat то же самое. Не зря его часто меняют на что-то другое: FluentD или Vektor.
В целом, эту ситуацию не трудно разрулить и даже автоматизировать настройку. Тут ключевой параметр - количество оперативной памяти, которую потребляет один рабочий процесс php-fpm. Это всегда будет зависеть от конкретного сайта. Вычисляется он, а потом по цепочке выстраивается потребление памяти всех остальных приложений. Затем обязательно настраивается ограничение запросов с одного IP. Потом результат тестируется стресс тестами и фиксируется. После этого для вас будут представлять опасность только DDOS атаки, которые на уровне одного сервера уже не отбить.
#webserver