PHP-процесс исчез, выгрузка оборвалась или сайт вернул 502? Сообщение Killed и код выхода 137 ещё не доказывают OOM — завершение из-за нехватки памяти. Нужны записи ядра или события контейнера за тот же интервал, связанные с нужным процессом.
Сначала сохраните время сбоя, PID и журналы, затем определите уровень ограничения: PHP, контейнер или весь сервер. Увеличивать memory_limit до этой проверки опасно: несколько обработчиков могут вместе исчерпать память, даже если каждый укладывается в свой предел.
1. Сохраните признаки до перезапуска
Зафиксируйте время с часовым поясом, URL или имя задания, PID процесса, имя контейнера и недавние изменения. Для CLI код завершения можно получить командой echo $? сразу после сбоя; другая команда уже заменит это значение.
Если посетители видят 502 Bad Gateway, сопоставьте ошибку прокси с журналом PHP-FPM. Сам HTTP-код не указывает, почему пропал обработчик.
Не воспроизводите тяжёлый импорт на рабочем сайте ради доказательства. Сначала соберите уже имеющиеся записи: после пересоздания контейнера часть диагностических данных исчезнет.
2. Отделите лимит PHP от OOM ядра
Проверьте журнал PHP и стандартный поток ошибок процесса:
Allowed memory size … exhaustedуказывает на ограничение памяти внутри PHP;Hard memory limit … exhaustedв версиях с таким механизмом означает немедленное завершение самим PHP; возможен код 137 без OOM ядра;Killedбез пояснений требует проверки журналов ОС и среды запуска.
Проверьте версию и действующие настройки именно того обработчика, который упал: конфигурация CLI и PHP-FPM может различаться. Не публикуйте phpinfo() на общедоступной странице.
Поведение лимитов зависит от версии: детали описаны в руководстве PHP. Отсутствие записи в обычном PHP error log само по себе не подтверждает OOM: сообщение могло попасть в stderr или процесс завершился до штатной обработки ошибки.
3. Найдите событие в журнале Linux
На сервере с systemd администратор может прочитать журнал ядра за интервал сбоя. Пример ниже показывает последние полчаса; для старого инцидента задайте точные границы времени.
sudo journalctl -k --since "30 minutes ago" --no-pager
Ищите сообщения Out of memory, oom-kill, Killed process, затем сопоставляйте PID, имя процесса и время. Не ограничивайтесь поиском слова PHP: память мог занять другой сервис, а ядро выбрало PHP жертвой.
Различайте нехватку памяти на хосте и ограничение cgroup — группы процессов с общим ресурсным пределом. Свободная RAM на сервере не исключает OOM внутри такой группы. Текущие показатели после завершения процесса тоже не показывают, сколько памяти было в момент аварии.
Если чтение журнала запрещено, запросите у хостинга проверку за конкретное время. Пустой вывод или недоступный журнал — недостаток данных, а не доказательство отсутствия OOM.
4. Проверьте контейнер и его предел
Для Docker используйте имя пострадавшего контейнера вместо CONTAINER:
docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}} {{.State.FinishedAt}}' CONTAINER
docker inspect --format '{{.HostConfig.Memory}}' CONTAINER
Значение OOMKilled=true — признак OOM, который нужно сопоставить с временем и журналом хоста. HostConfig.Memory показывает заданный предел Docker в байтах; ноль означает отсутствие этого явного предела, но не безграничную память.
Код 137 совместим с SIGKILL, но не объясняет причину: процесс могли принудительно остановить вручную или после истечения срока штатного завершения. Это различие следует из справки Docker о кодах завершения.
В cgroup v2 администратор проверяет файлы memory.max, memory.current и memory.events именно нужной группы: это предел, текущее потребление и счётчики событий. Рост счётчика oom_kill подтверждает OOM-завершения процессов в ней, но счётчик накопительный и сам по себе не называет PHP или время события. Сравнивайте снимки до и после инцидента и учитывайте дочерние группы: описание счётчиков Linux.
Не подставляйте случайный путь из чужой инструкции: cgroup v1, v2 и контейнерные пространства имён показывают разные структуры. Если убит только дочерний PHP-процесс, контейнер может продолжить работу — отсутствие перезапуска не закрывает проверку.
5. Выберите изменение и проверьте тот же сценарий
После подтверждения причины меняйте один фактор:
- Лимит отдельного задания PHP. Измерьте расход памяти на тестовой копии данных; разбейте импорт на порции или уберите загрузку всей выборки в память.
- Предел контейнера. Сравните потребление всех его процессов с доступным ресурсом хоста. Изменение лимита согласуйте с общей нагрузкой: контейнер не получает дополнительную физическую RAM автоматически.
- Нехватка памяти сервера. Проверьте конкурирующие задания и число обработчиков. Если насыщен пул, используйте отдельную диагностику очереди PHP-FPM.
Не отключайте OOM killer как способ восстановления: документация Docker предупреждает о риске для остальных процессов хоста. Перед повтором задания выясните, не успело ли оно частично записать данные: слепой повтор импорта способен создать дубли.
Проверьте результат на сопоставимом объёме и параллельной нагрузке: задание завершается, новых OOM-событий нет, сайт отвечает ожидаемым кодом и содержимым. Внешний мониторинг Web-Puls помогает заметить недоступность, но не читает память хоста и не устанавливает причину OOM.
Если доступа к журналам нет или сбой повторяется, отправьте заявку на диагностику: укажите публичный URL, время, сценарий и обезличенные фрагменты ошибок. Для выбора способа связи есть контакты; пароли, Cookie и содержимое пользовательских заявок передавать не нужно.