Сервис, который перестал отвечать, но живёт и ест процессор, лечится методично: сначала журналы, затем метрики, и только если оба инструмента не дают ответа, смотрят внутрь. Именно туда попадает strace: это не волшебная кнопка, а окно в разговор процесса с ядром, и чтение этой беседы показывает, чем процесс занят прямо сейчас, без перезапуска и без остановки службы. Разберём реальные приёмы: как подключиться к живому процессу, на что смотреть в потоке вызовов, как отличить зависание от работы и как делать это на боевой машине аккуратно.
Когда стоит смотреть в живой процесс а не в логи
Журналы отвечают, если программист предусмотрел подробный вывод, а именно этого часто не происходит в критическом обиходе, когда событие никто не ожидал. Метрики отвечают на вопрос, сколько, а не на вопрос, что. Остаётся окно в ядро: каждый процесс общается с системой через вызовы, и поток этих вызовов по своей форме рассказывает историю лучше любого отчёта об ошибках. Ждёт ли процесс данные по сети, борется ли за файл, падает ли при открытии конфигурации - всё это видно стеком вызовов.
Практический критерий решения звучит так: если по журналу и метрикам непонятно, отвечает ли служба на внешние запросы или просто живёт, тогда смело подключаемся к её процессу. Служба, которая отвечает и принимает подключения, говорит об этом через вызовы accept и epoll, а их профиль при нормальной работе виден на глаз. Служба, повисшая на файле, сообщает это потоком попыток открыть один и тот же путь. Программа с сетевой задержкой рисует повторный вызов connect с постоянным таймаутом. Все три сценария диагностируются за единицы минут без перезапуска ни одного процесса.
Подключение и семья фильтров по вызовам
Подключение к живому процессу делается ключом -p с номером процесса. Для многопоточных программ к этому добавляется флаг следования за потомками и флаг отслеживания иных видов действий, а ограничение позволяет смотреть вызовы, связанные только с файловой системой или только с сетью. На загруженном сервере фильтрация особенно важна: общий поток вызовов рабочего сервиса состоит на девяносто девять процентов из эфемерного чтения и записи, а фильтр позволяет выделить редкие значимые действия.
strace -p 4237 -f -tt -e trace=openat,connect,read,write -o /tmp/svc.trace -s 200
# сводка по вызовам за десять секунд трассировки
strace -p 4237 -c -o - 2>/tmp/svc.summary
Первый вызов записывает подробности в файл с метками времени и увеличенной длиной строк, важных при отладке путей. Второй собирает статистику по типам вызовов: какой из них занимает больше всего времени и сколько раз вызывается. Вместе они образуют рабочую пару: сводка указывает на аномалию, подробный след показывает точные аргументы вызовов.
Важна и позиция подключаемого: подключаться к процессу можно с тем же пользователем или с правами суперпользователя, а иногда и то и другое отказывает, потому что в современных системах по умолчанию ограничен доступ к трассировке через параметр ядра. При работе на чужих серверах стоит быть готовым к тому, что администрация потребует временного разрешения, и вопрос прав лучше решить до начала инцидента, а не во время.
Типовые картины зависания и порядок сводки
Опыт с strace учит распознавать несколько повторяющихся картин. Первая это ожидание ответа сервера: длинная черта вызовов read на сетевые дескрипторы устойчиво занимает секунды на каждый вызов, и весьма вероятно, что служба простаивает в ожидании недоступного сервиса на другом конце. Вторая это цикл попыток на несуществующий файл: повторяя openat с ошибкой нечасто, служба обнажает свой недоступный путь к конфигурации. Третья это конфликт при доступе к общему ресурсу: futex в потоке сообщений выглядит как признак блокировки, и процессор остаётся свободным, хотя служба недвижна снаружи. На этих картинах проще всего учиться, когда разбор идёт вживую, а не по воспоминаниям на следующее утро.
Отдельная группа историй связана с производительностью: Отдельный любопытный сигнал это вызов connect с кодом отказа по недоступному семейству адресов: приложение получает привязку к чужому узлу в одиночной форме, и при одном узле пуле новых адресов всё выглядит ресурсным вопросом, а не сетевым. На такой картине процесс сыпет ошибками доступности, и устаканить его можно заменой привязки на корректную конфигурацию пула, а не перезапусками.
процесс, делающий вид короткой работы, может тратить основное время на вызовы к синхронному диску или на бесплодные запросы к DNS-сервисам, причём та же история на метриках выглядит как невинный пик потребления процессора. Разбор потока вызовов переводит машинный язык в историю поведения: время на запись уходит в один файл, начало жизни идёт в prioridad настроек имён, а перерасход процессора живёт в повторяющемся пересчёте одного и того же списка.
После нескольких инцидентов для strace складывается привычный набор. Подключение со сводкой на минуту даёт первую картину без ущерба производительности, а подробная трассировка в файл берётся только после того, как сводка показала аномалию. Отдельной привычкой служит защита файлов правами: вывод в файл записывает пути, к которым обращается процесс, и любые привязанные к ним данные, поэтому Трассировка удаляется после разбора, а не забывается на общих серверах.
При подробном чтении удобно фильтровать вручную. Поиск по имени собственного процесса в логе отвечает на вопросы о запуске подчинённых Подробный след раскрывается вызовами: флаги, пути, дескрипторы и коды возврата намекают не только на то, что происходит, но и на то, как это устроено. На запись следует смотреть числами: время одного вызова чтения на несколько секунд и код возврата с числом байтов говорят больше, чем показательные графики, поиск по адресам файловой системы отвечает на вопросы о конфигурации, а поиск по признаку сетевого дескриптора врёт о клиентах. Из практики на будущее остаются несколько регулярных правил:
- начинать всегда со сводки на несколько секунд, прежде чем некоторые из нас детального отбора;
- при трассировке ключевых служб повышать буфер записи и заранее очистить место в каталоге временных файлов;
- в конце разбора удалять файлы трассировки, потому что они и живут как "второй журнал", и при этом могут содержать чувствительные строки конфигураций;
- при невыясненном затруднении возвращаться к трассировке через час: картина имеет свойство изменяться со временем суток и нагрузкой.
Такие приёмы звучат скучно, но именно они отличают спокойный и обратимый инструмент от сочетания нагрузки и стресса и от случайных ухудшений, которое нельзя перепроверить на стенде.
Типовой сеанс на сервере с недоступным сервисом
Наиболее показательная сессия выглядит так. Точка обслуживания перестала отвечать через полчаса после неожиданной волны трафика. Сначала смотрим журнал: без изменений, последняя запись вчерашняя. Метрики на графиках показывают стопроцентный процессор, но никакой истории отказов внешних служб. Подключаемся к живому процессу strace со сводкой, и видим: процессор горит на частоте в тысячи ничтожных вызовов чтения на несуществующий файл, а между текущим конфигурационным файлом и фактической системой лежит устаревший путь. Одна символическая ссылка, построение картины заново, и служба возвращается к жизни за две минуты, без перезапуска.
Те же картины встречаются в отчётах. Первая это время, проведённое в вызове connect к недостам семейной службе: система подвисала бы вечно, пока бы приложение не отказалось отбирать вызовы до очистки таймера. Вторая это циклическая запись в файл, добавляющий классовый мусор без проверки свободного места на диске: процессор отправляет в лог миллион строк, а служба выглядит как неработающая, потому что каждый следующий шаг ждёт записи. Третья это блокировка файлов: процесс ожидает получить блокировку, которую никогда не снимет процесс на соседнем узле. Чтение таких привычек намного короче их возникновения.
Чем strace отличается от ltrace и таких программ
Strace показывает диалог процесса с ядром: вызовы, и ничего больше. Поэтому вопросы про внутренние циклы программы он не решает. Когда нужно видеть библиотечные вызовы вроде функций шифрования или функций обращения к данным, работа отдаётся ltrace, она следит за вызовами библиотек в пользовательском режиме. Есть и ловушка: ltrace в текущих дистрибутивах в лучшем случае второй необходимости, потому что почти всё производственное наблюдение начинается и заканчивается ядром, зависаниями служб и системными вызовами, а не тонкостью внутренних функций.
Те же принципы отвечают на вопрос "где сломалось?". strace отвечает быстрее любого другого инструмента на вопросы про журналы, метрики и холодные процессы, а когда вопрос начинается со слова "зависла", подключение к живому процессу чаще всего вскрывает причину за одну минуту. Неудивительно, что она стала первой полусистемной привычной техникой у администраторов со значительным стажем.
Производительность и аккуратность на живой машине
Разговор процесса с ядром дорого трогать прослушиванием, потому что каждая запись вызова это задержка. На тихой машине фатальной алчности нет, на загруженных боевых серверах трассировку на периоды придерживают до коротких окон. Упоминания при этом не пустые: сборка сводка на тридцать секунд перебирается за минуты без вреда, а полная трассировка с выводом всех вызовов под нагрузкой приостанавливает не только производительность, но и разум разбирающего, которому потом приходится читать сотню тысяч строк.
Поэтому на боевых системах работают принципы умеренности: первый проход краток и сводчатый, второй фильтрованный, третий детальный. Между запусками следят за воздействием на сам наблюдаемый процесс, и та же осторожность остаётся при наблюдении за кластером, где один проход на каждом узле выводит картину, а избыточная трассировка остаётся лишним риском. Из прикладных деталей здесь стоит два важных соглашения. Первое это объём файла трассировки: на загруженном узле трассировка растекается в мегабайты за минуты, и писать её стоит на достаточно быстрый диск, потому что в противном случае растёт дополнительная нагрузка на уже напряжённый узел. Второе это право на сами данные: файлы трассировки содержат пути, операции и иногда контент буферов, и работать с ними стоит так, как работают с уведомлениями без обучения.
Что смотреть до strace и что после него
Порядок инструментов в диагностике всегда одинаков: журналы, метрики нагрузки, внешние признаки, и только потом втяжки в ядре. До strace стоит взглянуть на /proc: стек процесса в точке замечания, открытые к его дескрипторы, карты памяти. Часто этих трёх ответов достаточно для предварительного диагноза, и только если объяснение не складывается, открывается поток вызовов. Именно этот порядок отделяет грамотную диагностику от стрельбы из пушки по воробьям: чем позже в дело включается подробный след, тем меньше нагружается узел, и тем легче уменьшить обратное влияние, пусть порой и приходится повторять сбор данных, пока картина не станет объяснимой.
После strace диагностика продолжается, и в ней уже важнее не инструмент. Понимание, найденное при трассировке, проверяется на отдельном стенде, изменение внедряется исправлением конфигурации или пересмотром хронографии, а по итогу стоит отдохнуть от инцидента не только инженеру, но и службе, и команде. Знание порядка диагностических инструментов критично для предсказуемости, а не для скорости: покрылись одни и те же места вопросов, которые оседают, когда трассировка уже отработала.
Контрольный последний аккорд простой. Зависание на живом сервисе перестаёт пахнуть ужасом, когда у него появляется ритуал: показатель, трассировка, разбор, маленькое изменение, проверка. Признак зрелого хозяйства здесь не загадочные инструменты, а привычка фиксировать: об инциденте не молчат, а пишут его номер и уроки, и следующее зависание решается вдвое быстрее. А сам инструмент в таком хозяйстве выглядит скромной, но аварийно чистым молотком в ящике с наборами: стоит перед глазами, приходит к делу редко, но всегда вовремя.