Порядок диагностики
Сначала смотрят, потом перезапускают — иначе улики пропадут.
- Жив ли процесс —
systemctl status app,ps aux | grep app. - Логи —
journalctl -u app --since "10 min ago", файлы приложения. - Ресурсы —
top,free -m,df -h,iostat -xz 1. - Сеть —
ss -tlnp(слушает ли порт),curl localhost:8080/health. - Что изменилось — деплой, конфиг, истёкший сертификат.
strace -p PID показывает, что процесс делает прямо сейчас. Перед перезапуском зависшего сервиса полезно снять дамп потоков — он понадобится для разбора.
Load average
Три числа — среднее за 1, 5 и 15 минут числа процессов, которые выполняются или ждут CPU, а в Linux ещё и ждут ввода-вывода. Сравнивают с числом ядер:
- load 8 на 16 ядрах — нормально;
- load 8 на 2 ядрах — очередь.
Если первое число больше третьего, нагрузка растёт. Высокий load при свободном процессоре — признак ожидания диска или сетевой файловой системы. В top смотрят на wa (ожидание ввода-вывода) и st (время, украденное гипервизором соседям).
Память
Linux занимает свободную память под кэш файлов, поэтому free почти всегда мал. Смотрят на available — сколько можно выделить, вытеснив кэш:
free -m
# total used free shared buff/cache available
# Mem: 7972 3120 210 45 4642 4520
Здесь свободно не 210 МБ, а около 4,5 ГБ.
Когда память действительно кончилась, OOM killer убивает процесс с наибольшей оценкой — обычно самый большой. Следы — в логе ядра:
dmesg -T | grep -i "killed process"
В контейнере OOM срабатывает при превышении лимита cgroup, даже если на хосте память есть.
Состояния процессов
В ps видно состояние процесса:
| Код | Что значит |
|---|---|
| R | выполняется или ждёт процессор |
| S | спит в ожидании события — норма |
| D | непрерываемый сон, ждёт диск или сеть; не реагирует даже на SIGKILL |
| T | остановлен |
| Z | зомби |
Зомби — процесс завершился, но родитель не забрал код выхода. Памяти он не занимает, только запись в таблице процессов, и убить его нельзя — исправляют или перезапускают родителя. Тысячи зомби исчерпывают лимит PID. В контейнере без init зомби собирать некому — для этого ставят tini.
Много процессов в состоянии D — проблема с диском или NFS, и они же поднимают load average.
Диск заполнен, а du показывает мало
df считает место на файловой системе, du — сумму видимых файлов. Если они расходятся, почти всегда виноват удалённый файл, который ещё держит открытым процесс — например, лог после ротации:
lsof +L1 # открытые удалённые файлы
du -xh --max-depth=1 / | sort -h # где большие каталоги
df -i # не кончились ли inodes
Место освобождается после перезапуска процесса. Чтобы проблема не повторялась, ротацию логов настраивают с перезапуском или copytruncate. Вторая частая причина — кончились inodes из-за множества мелких файлов. Для Docker — docker system df: старые образы и логи контейнеров.
Что запомнить
- Сначала данные и логи, потом перезапуск.
- Load average сравнивают с числом ядер.
- Свободная память — колонка available.
- Зомби лечат через родителя.
- df больше du — ищите удалённые открытые файлы.