Стройте ответ вокруг владения состоянием, лимитов, отказа и восстановления. Определение становится инженерным ответом только в конкретном production-сценарии.
Вопросы и ответы
11 подробных ответов
01Load average 30, а CPU почти простаивает. Сервер перегружен? Что будете проверять?
senior
Короткий ответ: Не обязательно. В Linux load average считает не только runnable-процессы, но и задачи в uninterruptible sleep (D-state) — обычно это ожидание дискового или NFS I/O. Load 30 при простаивающем CPU почти всегда означает проблему с I/O, а не нехватку ядер.
Подробно:
- Особенность Linux — в отличие от других Unix, load average включает D-state задачи. 30 процессов, зависших на мёртвой NFS-шаре, дадут load 30 при нулевом CPU.
- Ищем D-state —
ps -eo stateили top: у виновников статусD. - Смотрим диски —
iostat -x: %util под 100 и большой await = диск захлёбывается. - Проверяем NFS — зависший маунт держит процессы в D-state бесконечно.
uptime # load: 30.2 29.8 28.5
top # %Cpu(s): ... 95 id → CPU ни при чём
ps -eo pid,state,wchan:30,comm | awk '$2=="D"'
iostat -x 1 3 # %util, await по каждому диску
mount -t nfs,nfs4 # есть ли NFS-маунты, живы ли они
⚠️ Частая ошибка: считать load average мерой загрузки CPU и предлагать «добавить ядер». Если load создают D-state задачи, апгрейд CPU не изменит ничего — узкое место в I/O.
02Процесс убил OOM-killer. Как ядро выбирает жертву и как защитить критичный процесс?
senior
Короткий ответ: Ядро считает каждому процессу oom_score — грубо, процент занимаемой памяти — и убивает процесс с максимальным. Скор сдвигается через oom_score_adj (−1000…+1000). Запись об убийстве ищите в логе ядра: dmesg или journalctl -k.
Подробно:
- Где след — приложение получает SIGKILL и не успевает ничего залогировать; запись оставляет ядро: «Out of memory: Killed process 1234 (java)…».
- oom_score — примерно доля используемой памяти (RSS + swap): чем больше процесс ест, тем привлекательнее жертва.
- oom_score_adj — ручной сдвиг: −1000 полностью исключает процесс из выбора, +1000 делает первым кандидатом. Kubernetes ставит Guaranteed-подам −997.
- cgroup-лимиты — memory limit на cgroup локализует OOM: жертва выбирается внутри группы-нарушителя, а не среди случайных соседей по хосту.
dmesg -T | grep -i 'killed process'
journalctl -k --since '1 hour ago' | grep -i oom
cat /proc/1234/oom_score /proc/1234/oom_score_adj
echo -900 > /proc/1234/oom_score_adj # или OOMScoreAdjust=-900 в systemd-юните
⚠️ Частая ошибка: искать причину падения в логах приложения. SIGKILL нельзя перехватить — там будет тишина; смотреть нужно лог ядра.
03«No space left on device», но df показывает свободное место. Назовите две классические причины.
middle
Короткий ответ: Чаще всего либо кончились inode — место есть, а записать метаданные нового файла некуда, — либо вы упёрлись в блоки, зарезервированные под root: ext4 по умолчанию держит ~5% недоступными обычным пользователям.
Подробно:
- Inode exhaustion —
df -iпокажет IUse% = 100%. Типичный виновник — миллионы мелких файлов: кэши сессий, почтовые очереди, артефакты сборок. Лечится поиском и чисткой каталога-рассадника; по размеру вdf -hего не видно. - Резерв под root — df показывает свободные гигабайты, но обычному пользователю ENOSPC, а root пишет успешно — верный признак. Проверить
tune2fs -l, уменьшить резервtune2fs -m 1.
df -h /data # Use% 95% — место вроде есть
df -i /data # IUse% 100% → кончились inode
du --inodes -d1 /data | sort -n | tail # где живут миллионы файлов
sudo tune2fs -l /dev/sdb1 | grep -i 'reserved block'
⚠️ Частая ошибка: остановиться на df -h и заключить «место есть, значит баг приложения». df -i — обязательный второй шаг при любом ENOSPC.
04Вы удалили лог на 50 ГБ, но место не освободилось. Почему и как вернуть его без рестарта процесса?
middle
Короткий ответ: Файл всё ещё открыт процессом: rm убирает имя из каталога, но данные живут, пока открыт последний файловый дескриптор. Найти виновника — lsof +L1; вернуть место без рестарта — обнулить файл через /proc/<pid>/fd/N.
Подробно:
- Механика — место освобождается, когда счётчик ссылок стал 0 И никто не держит fd. df считает такие «удалённые, но открытые» файлы занятыми, du их уже не видит — отсюда классическое расхождение df vs du.
- Диагностика —
lsof +L1показывает открытые файлы с link count 0: процесс, номер fd и размер. - Вернуть место сейчас — truncate через procfs:
: > /proc/<pid>/fd/Nобнуляет содержимое, не трогая процесс. - Чтобы не повторилось — copytruncate в logrotate или сигнал приложению переоткрыть лог (у nginx —
kill -USR1).
df -h /var/log && du -sh /var/log # df видит 50 ГБ, du — нет
lsof +L1 | grep deleted
# nginx 1234 ... 5w ... 53687091200 /var/log/access.log (deleted)
: > /proc/1234/fd/5 # место вернулось, процесс живёт
⚠️ Частая ошибка: перезапускать сервис в прайм-тайм ради 50 ГБ. truncate через /proc возвращает место мгновенно и без даунтайма.
05`free` показывает почти ноль свободной памяти. Сервер задыхается без RAM?
junior
Короткий ответ: Почти наверняка нет. Linux сознательно занимает «лишнюю» память под page cache — она отдаётся приложениям мгновенно. Смотреть надо на колонку available, а не free; о реальном дефиците говорят swap-in и major page faults.
Подробно:
| Метрика | Что означает | Тревожиться? |
|---|---|---|
| free | память, не занятая вообще ничем | нет — у здорового сервера близка к нулю |
| buff/cache | page cache: кэш файлов и блоков | нет — вытесняется по требованию |
| available | сколько реально можно выдать без свопа | да, если стабильно стремится к нулю |
- Пустая память — потерянная память — ядро кэширует диск, чтобы повторные чтения шли из RAM, а не с устройства.
- Реальные признаки дефицита — растущий si в
vmstat 1(swap-in), major page faults, срабатывания OOM-killer в dmesg.
free -h # смотрим available, не free
vmstat 1 5 # колонки si/so — идёт ли активный своппинг
⚠️ Частая ошибка: «свободной памяти нет — перезагрузим» или сброс кэша через drop_caches. Page cache — это фича: очистка только замедлит систему до повторного прогрева.
06Что такое процесс-зомби, почему kill -9 на него не действует и когда зомби становятся проблемой?
junior
Короткий ответ: Зомби — завершившийся дочерний процесс, чей exit-статус родитель ещё не забрал через wait(). От процесса осталась только запись в таблице процессов: ни кода, ни памяти. Поэтому kill -9 бессмысленен — сигнал шлётся тому, что уже мертво.
Подробно:
fork() → работает → exit() → ZOMBIE (запись в таблице процессов)
│ родитель вызывает wait()
▼
запись удалена (reaped)
- Причина всегда в родителе — он не вызывает wait()/waitpid() и игнорирует SIGCHLD. Чинится исправлением или рестартом родителя: осиротевшие зомби переходят к init/systemd, который немедленно их пожинает.
- Ресурсов зомби не ест — ни CPU, ни памяти; занимает только PID и строку в таблице.
- Когда это проблема — массовая утечка зомби исчерпывает пространство PID (kernel.pid_max): fork начинает отказывать всем процессам на хосте.
ps -eo pid,ppid,state,comm | awk '$3=="Z"' # кто зомби и кто родитель
⚠️ Частая ошибка: пытаться «убить» зомби сигналами. Единственный путь — заставить родителя вызвать wait() или перезапустить самого родителя.
07Процесс висит в D-state и не умирает даже от kill -9. Почему и что делать?
senior
Короткий ответ: D-state — uninterruptible sleep: процесс находится внутри системного вызова и обычно ждёт I/O (мёртвая NFS-шара, умирающий диск). Сигналы, включая SIGKILL, доставляются только по возвращении из syscall — пока I/O не завершится или не оттаймаутится, убить процесс невозможно.
Подробно:
- Это защита, а не баг — прерывание процесса посреди операции с ядром и железом оставило бы структуры данных в неконсистентном состоянии.
- Смотрим, где застрял —
cat /proc/<pid>/stack(стек в ядре) и колонка wchan в ps: функция ядра, в которой спит процесс, указывает на подсистему — NFS, block layer. - Лечим причину, а не процесс — поднять NFS-сервер,
umount -f/umount -lдля мёртвой шары, проверить диск: dmesg на I/O errors, SMART. - Если I/O не вернётся никогда — процесс освободит только перезагрузка.
ps -o pid,state,wchan:32,comm -p 1234 # в какой функции ядра спит
cat /proc/1234/stack # kernel-стек (нужен root)
dmesg -T | tail -30 # ошибки диска, NFS-таймауты
⚠️ Частая ошибка: эскалация kill → kill -9 → «почему не работает?!». SIGKILL здесь бессилен by design — искать нужно зависший I/O, а не более сильный сигнал.
08strace и perf: когда берёте каждый из них и какова цена использования на проде?
middle
Короткий ответ: strace — трассировка системных вызовов: отвечает «на чём процесс висит, какие файлы и сокеты трогает». perf — сэмплирующий CPU-профайлер: отвечает «куда уходят такты». strace через ptrace замедляет цель в разы — на проде с осторожностью; perf стоит единицы процентов.
Подробно:
| strace | perf | |
|---|---|---|
| Механизм | ptrace: остановка на каждом syscall | сэмплирование по таймеру/PMU |
| Вопрос | «что делает / где застрял» | «где горит CPU» |
| Оверхед | огромный: ×10–100 на syscall-интенсивных | низкий, обычно 1–5% |
| Типовой кейс | висит на connect? какой конфиг читает? откуда EACCES? | горячие функции, flamegraph |
strace -f -tt -T -p 1234 # живой поток syscalls с таймингами
strace -c -p 1234 # сводка: счётчики и время по вызовам
perf top -p 1234 # горячие функции прямо сейчас
perf record -g -p 1234 -- sleep 30 && perf report # профиль со стеками
⚠️ Частая ошибка: повесить strace на нагруженный прод-сервис «просто посмотреть» — латентность может вырасти на порядок. Для вопроса «куда уходит CPU» сначала perf; strace — прицельно и коротко.
09В проде сыпется «Too many open files». Опишите полный путь диагностики.
middle
Короткий ответ: Сначала понять, в какой лимит упёрлись: per-process (ulimit -n / LimitNOFILE) или системный fs.file-max. Затем посчитать и классифицировать дескрипторы процесса — и найти утечку. Поднимать лимит — только после ответа на вопрос «почему их столько».
Подробно:
- Какой лимит — у процесса свой:
cat /proc/<pid>/limits. Для systemd-сервисов ulimit из шелла не действует — правит LimitNOFILE в юните. Системный потолок —fs.file-max. - Сколько открыто —
ls /proc/<pid>/fd | wc -lпротив лимита процесса. - Что именно открыто — lsof по процессу: тысячи сокетов в CLOSE_WAIT = приложение не закрывает соединения; тысячи одинаковых файлов = утечка fd в коде.
- Только теперь лимит — если рост легитимный (нагрузка выросла), поднять LimitNOFILE и при необходимости fs.file-max.
cat /proc/1234/limits | grep 'open files'
ls /proc/1234/fd | wc -l
lsof -p 1234 | awk '{print $5}' | sort | uniq -c | sort -rn | head
systemctl show myapp -p LimitNOFILE
sysctl fs.file-max fs.file-nr
⚠️ Частая ошибка: молча поднять лимит в 10 раз. Если это утечка дескрипторов, вы лишь отложили инцидент — и сделали его разбор тяжелее.
10Что такое iowait и всегда ли высокий iowait означает проблему с диском?
middle
Короткий ответ: iowait — время, когда CPU простаивает, ПОКА у него есть незавершённый дисковый I/O. Это разновидность idle, а не работа. Высокий iowait говорит «нагрузка ждёт диск», но сам по себе не доказывает, что диск — узкое место: подтверждать нужно через iostat -x.
Подробно:
- Определение — ядро помечает такт как iowait, если ядро CPU свободно, но на нём есть задача, заблокированная на I/O. Будь у CPU другая работа — он бы её выполнял.
- Следствие №1 — высокий iowait означает запас CPU: такты свободны, добавленная вычислительная нагрузка выполнится.
- Следствие №2 — на загруженном CPU дисковая проблема прячется: iowait низкий, потому что CPU занят другим, хотя диск так же плох.
- Подтверждение диска —
iostat -x: %util к 100, await заметно выше базовой латентности устройства, растущая очередь aqu-sz. Кто генерит I/O —pidstat -d/ iotop.
mpstat 1 5 # %iowait по ядрам
iostat -x 1 5 # %util, r_await/w_await, aqu-sz
pidstat -d 1 # I/O в разрезе процессов
⚠️ Частая ошибка: реагировать на цифру iowait без iostat. iowait — симптом сочетания «нагрузка ждёт I/O при свободном CPU», а не метрика здоровья диска.
11Диск заполняется прямо сейчас, гигабайты в час. Как найдёте виновника — по шагам?
middle
Короткий ответ: Сначала сверить df с du: если df видит занятое, а du — нет, место держат удалённые-но-открытые файлы или другие маунты. Дальше сузить каталог через du/ncdu, найти растущие файлы по mtime и проверить типовых подозреваемых: логи без ротации, journald, докер-слои.
Подробно:
- df vs du —
lsof +L1на удалённые открытые файлы; убедиться, что поверх каталога ничего не смонтировано и не прячет старые данные. - Сузить каталог —
du -xh -d1 / | sort -hили ncdu -x: флаг -x не даёт уйти на другие файловые системы. - Что растёт прямо сейчас —
find / -xdev -mmin -10 -size +100M: большие файлы, изменённые за последние 10 минут, почти всегда и есть виновник. - Типовые подозреваемые — приложение, внезапно включившее debug-логирование; journald без лимита (
journalctl --disk-usage); слои и логи контейнеров (docker system df).
df -h / && du -xsh / # сходятся ли цифры
lsof +L1 | grep deleted
du -xh -d1 / 2>/dev/null | sort -h | tail
find / -xdev -mmin -10 -size +100M -ls 2>/dev/null
journalctl --disk-usage && docker system df
⚠️ Частая ошибка: сразу удалять «что-нибудь большое». Пока источник роста не найден, освобождённое место съедается за минуты — сначала найти писателя, потом чистить.
Источники
Источники и редакционная политика
Материалы RecallDeck сопоставлены с официальной документацией и открытыми публикациями компаний, когда первичный источник доступен. Мы не связаны с упомянутыми работодателями, не публикуем конфиденциальные задания и не продаём места в подборках. Формат найма может меняться — уточняйте его у рекрутера.
От чтения к воспроизведению
Отрепетируйте полный цикл интервью.
RecallDeck возвращает сложные темы по расписанию и помогает удерживать в памяти язык, SQL, архитектуру и поведенческие истории.