Экран загрузки был retry-циклом, а не зависанием — и ребут был не нужен
Игра на моей Linux-машине зависала на экране загрузки, и известным лекарством был полный ребут. Пять секунд счётчиков из /proc показали горячий retry-цикл, который заканчивается одним SIGTERM.
Эта история с моей собственной рабочей станции, а не из кластера, но урок напрямую переносится в продакшен.
Crimson Desert под Proton Experimental на Ubuntu иногда навсегда застревал на экране загрузки сохранения. Известным обходом был полный ребут машины. Происходило это «иногда», без очевидного триггера.
Висит или крутится?
Первый вопрос решает всё: процесс ждёт чего-то или жжёт CPU? Процесс в состоянии D заблокирован в ядре, обычно на вводе-выводе, и убить его нельзя. Процесс в состоянии R работает и умрёт от сигнала.
ps показывал R. По потокам — три потока загрузчика, каждый на 100 % CPU, и wchan у них 0: крутятся в user space, а не блокированы в ядре.
Решающий замер
Высокий CPU сам по себе цикл не доказывает: медленная загрузка тоже жжёт CPU. Доказывает прогресс. Я прочитал /proc/<pid>/io дважды с интервалом пять секунд:
| Сигнал | Дельта за 5 с |
|---|---|
read_bytes |
0 |
syscr |
+38 468 |
Около 7 700 системных вызовов чтения в секунду — и ни одного реально прочитанного байта. Лог игры называл ошибку: ReadFile падает с ошибкой Windows 6, ERROR_INVALID_HANDLE, и повторяется в бесконечном цикле без backoff и без лимита попыток. Экран загрузки ничего не ждал — он долбил чтения, которые не могли получиться никогда.
Исключено замером, а не догадкой
- зависший дисковый ввод-вывод — процессов в
Dнет, прочитано ноль байт, места полно; - зависание сети или облачных сохранений — исходящих соединений нет вовсе;
- нехватка памяти — свободно десятки гигабайт, swap не используется;
- битое сохранение — лог показал успешную загрузку сохранения до начала цикла; сбой начался примерно через восемь секунд, во время стриминга ассетов;
- зависание GPU — нагрузка на GPU была анимацией экрана загрузки и упала мгновенно, как только процесс исчез.
Фикс
Раз процесс был в R, хватило сигнала:
pkill -TERM -f CrimsonDesert.exe
Он чисто завершился по SIGTERM. Нагрузка на GPU упала с 99 % до 2 %. Ребут всегда был избыточен.
Что вызывает невалидный хэндл, пока неизвестно — вероятнее всего, гонка в стриминге ассетов игры или в экспериментальной сборке Proton. В следующий раз у меня будет включён PROTON_LOG=1, чтобы трасса назвала файл.
Выводы
RилиDрешает, нужен ли ребут вообще. Крутящийся процесс не завис.- CPU высокий + счётчики I/O стоят = retry-цикл. Замерьте дельту за несколько секунд, прежде чем хвататься за кувалду.
- Отбрасывайте гипотезы цифрами. Каждое «может, это диск / сеть / GPU» опровергалось одной командой.
- Тот же отпечаток встречается везде: init-контейнер, ретраящий неудачный mount, sidecar, ретраящий мёртвый эндпоинт, шаг CI, ретраящий 404.