сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Мониторинг и логи

Трассировка и золотые сигналы

Трассировка и золотые сигналы

Трассировка - это запись пути одного запроса через все сервисы, с отметками, что и когда происходило. Замерил одну и ту же работу двумя способами. Три вызова подряд: сумма длительностей 251 миллисекунда, запрос занял 251. Те же три вызова параллельно: сумма длительностей 252, а запрос занял 121. Сумма одинаковая, время пользователя разное вдвое. Из одних только длительностей это не видно - нужна картинка, кто кого ждал.

Стержень: трассировка показывает не сколько заняли шаги, а как они расположены во времени; сэмплирование определяет, увидишь ли ты вообще нужный случай.

// Формулировки: «зачем трассировка, если есть логи?», «как выбрать долю сэмплирования?», «что такое золотые сигналы?»

Спаны и картинка запроса

Спан - это отрезок работы с началом, концом и именем: «запрос к базе», «вызов сервиса цен». У спанов есть родитель, поэтому из них складывается дерево, а дерево разворачивается в картинку по времени. Именно картинка отвечает на вопросы, на которые не отвечают ни метрики, ни логи.

Мой замер это показывает буквально. Сумма спанов 251 миллисекунда в обоих случаях, но в первом шаги идут друг за другом, а во втором - одновременно, и запрос занимает 121. Если смотреть только на сумму, две ситуации неразличимы. На картинке видно сразу: лесенка означает последовательные вызовы, которые можно распараллелить, а длинный спан, начавшийся сразу и закончившийся последним, - это тот, кто держит весь запрос.

// Отсюда типичные находки в трассировках: три последовательных вызова, которые могли идти параллельно; повторяющийся одинаковый запрос к базе двадцать раз подряд; ожидание блокировки, которого не видно ни в одной метрике; чужой сервис, который отвечает за 800 миллисекунд при собственной работе в 30.

спан
отрезок работы с началом, концом, именем и родителем
дерево спанов
структура вызовов одного запроса; разворачивается в картинку по времени

Сэмплирование: сколько запросов оставлять

Хранить трассировку каждого запроса дорого, поэтому оставляют долю. Вопрос в том, какую, и он считается арифметикой. При 2000 запросах в секунду и доле 1% в трассировки попадает 20 запросов в секунду. Если сбоит 5% запросов, это 60 сбойных трассировок в минуту - разбирать есть что. А если сбоит 0,1%, то всего 1,2 в минуту, и редкий сбой можно ждать часами.

Ужесточим: при доле 0,1% и той же редкой поломке в трассировки попадает 0,1 случая в минуту, то есть один раз в десять минут. Именно поэтому «мы включили трассировку, но нужного случая там нет» - это не мистика, а арифметика.

// Решение известно: сэмплировать не случайно, а по результату. Сначала собрать спаны запроса, а решение о сохранении принять в конце: сохранить все запросы с ошибкой и все медленные, а из успешных и быстрых оставить небольшой процент. Тогда редкие сбои сохраняются целиком, а объём остаётся приемлемым. Плата - буфер, где спаны ждут решения, и сложность в самом сборщике.

сэмплирование
сохранение только доли трассировок
решение по результату
сохранять запрос или нет, решают в конце: ошибки и медленные - всегда

Три сигнала, которые меряют у всего

Есть короткий список того, что меряют у любого сервиса, чтобы понять его состояние. Нагрузка: сколько запросов в секунду приходит. Ошибки: какая доля запросов завершается неуспешно. Задержка: сколько занимает ответ, причём в квантилях (значениях, ниже которых лежит заданная доля запросов), а не в среднем - я это показывал числами, среднее 79 миллисекунд при квантиле 0,99 в 2318.

К этим трём часто добавляют четвёртый - насыщенность: насколько близко к пределу самый узкий ресурс. Очередь, запас заранее открытых соединений к базе, место на диске, свободная память. Смысл в том, что первые три показывают, что уже плохо, а насыщенность предупреждает, что скоро станет.

// Практическая ценность списка в том, что он одинаков для всего: для сервиса, для базы, для очереди. Не надо придумывать метрики заново для каждого компонента - берёшь эти четыре, и у тебя уже есть с чем сравнивать и на что вешать алерты. А дальше добавляешь то, что специфично именно для этого компонента.

нагрузка
сколько запросов приходит в секунду
задержка
время ответа; смотрят в квантилях, а не в среднем
насыщенность
насколько близко к пределу самый узкий ресурс

Как отвечать: «Зачем трассировка, если уже есть метрики и логи?»

Метрики отвечают на вопрос «что и насколько плохо», логи - «что случилось в конкретном месте», а трассировка отвечает на «где именно ушло время в этом запросе». Я это специально мерил: три вызова подряд дают сумму длительностей 251 миллисекунда и время запроса 251, а те же три вызова параллельно - сумму 252 и время запроса 121. По суммам ситуации неразличимы, а пользователь ждёт вдвое дольше. На картинке видно сразу: лесенка последовательных вызовов, повторяющийся одинаковый запрос к базе, ожидание блокировки, чужой сервис, который отвечает за 800 миллисекунд. И сразу оговорю сэмплирование, потому что на нём чаще всего разочаровываются: при одном проценте и редкой поломке в трассировки попадает около одного случая в минуту, поэтому решение о сохранении лучше принимать по результату - все ошибки и все медленные сохранять целиком.

Ответ разводит три инструмента по вопросам, на которые они отвечают, и подкрепляет измерением. Замечание про сэмплирование снимает главное разочарование от трассировки.

На чём валятся

  • Смотрят на сумму длительностей и не видят разницы между последовательными и параллельными вызовами.
  • Ставят случайное сэмплирование в один процент и не находят редкие сбои.
  • Не пробрасывают идентификатор трассировки в одном сервисе и получают обрубленное дерево.
  • Меряют задержку средним вместо квантилей.
  • Придумывают свой набор метрик для каждого компонента вместо общего короткого списка.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 6, остальные разбираются в тренажёре.

  1. #dvo_tracing1 / 5
    Трассы собирают с сэмплированием 1%. Что теряется и чем это компенсируют?
    A)Ничего: редкие запросы всё равно повторяются и попадут в выборку
    B)Теряется точность метрик, поэтому их считают из трасс заново
    C)Теряются редкие ошибки и хвост задержек
    D)Теряется связь с логами: идентификаторы перестают совпадать
    показать ответ и разбор
    +C)Теряются редкие ошибки и хвост задержек

    // разбор: Решение на входе (head-based) отбрасывает 99% запросов вслепую — вместе с редкими ошибками и медленными хвостами, ради которых трассировку и заводят. Сэмплирование по итогу (tail-based) держит трассу в буфере до завершения и сохраняет её, если запрос упал или превысил порог задержки, а из успешных быстрых берёт долю. Платить приходится памятью коллектора и сложностью настройки.

  2. #dvo_tracing2 / 5
    Мониторинг сервиса состоит из графиков CPU, памяти и диска. Что предлагает подход золотых сигналов?
    A)Добавить к ним сетевые метрики и число процессов
    B)Мерить трафик, ошибки, задержку и насыщенность ресурсов
    C)Перейти на проверки доступности раз в минуту из внешней точки
    D)Считать только доступность: остальное вторично
    показать ответ и разбор
    +B)Мерить трафик, ошибки, задержку и насыщенность ресурсов

    // разбор: Золотые сигналы описывают сервис глазами пользователя: сколько запросов приходит, какая доля падает, сколько ждут ответа (обязательно в квантилях, а не в среднем) и насколько близко ресурсы к пределу. Для очередей и пулов последний сигнал — самый ранний предвестник аварии. Метрики железа при этом никуда не деваются, но они объясняют причину, а не сигналят о проблеме.

  3. #dvo_tracing3 / 5
    Что технически представляет собой одна распределённая трасса и как она собирается через сервисы?
    A)Один большой лог-файл, склеенный со всех сервисов
    B)Копия запроса, продублированная в каждый сервис
    C)Метрика длительности запроса без разбивки по шагам
    D)Дерево спанов с общим trace-id
    показать ответ и разбор
    +D)Дерево спанов с общим trace-id

    // разбор: Трасса — дерево спанов: каждый спан описывает операцию (вызов сервиса, запрос к БД) с временем начала/длительностью, у всех общий trace-id, а parent-id задаёт родство. Чтобы спаны связались в одну трассу, между сервисами прокидывают trace-context — обычно в HTTP-заголовке (traceparent по W3C). Каждый сервис создаёт свой спан и передаёт контекст дальше. Так виден путь и вклад каждого шага в общую задержку.

  4. #dvo_tracing4 / 5
    Голова-сэмплинг оставляет случайный 1% трасс — и редкие ошибки/медленные хвосты как раз теряются. Что это лечит?
    A)Tail-based сэмплинг: решать после трассы
    B)Поднять head-сэмплинг до 100% и хранить всё
    C)Снизить head-сэмплинг ещё сильнее ради экономии
    D)Сэмплировать по имени сервиса, а не по проценту
    показать ответ и разбор
    +A)Tail-based сэмплинг: решать после трассы

    // разбор: Head-based сэмплинг решает судьбу трассы в самом начале, вслепую, поэтому случайный 1% почти не содержит редких ошибок и хвостовых задержек. Tail-based сэмплинг откладывает решение до конца трассы: увидев исход (ошибка, высокая latency), он сохраняет все «интересные» трассы и прореживает рутинные. Цена — надо буферизовать спаны до решения (сложнее инфраструктурно), зато в хранилище попадает именно то, что нужно для разбора.

  5. #dvo_tracing5 / 5
    Трасса аккуратно проходит по синхронным вызовам, но обрывается, как только запрос уходит в очередь и обрабатывается воркером. Почему?
    A)Трассировка вообще не работает с очередями
    B)Воркер обязан читать trace-id из общей базы
    C)Trace-context не прокинут через сообщение — воркер начинает новую трассу
    D)Очередь сбрасывает trace-id по соображениям безопасности
    показать ответ и разбор
    +C)Trace-context не прокинут через сообщение — воркер начинает новую трассу

    // разбор: Через синхронный HTTP trace-context прокидывается заголовком, а вот на границе очереди он теряется, если его не положить в метаданные/заголовки самого сообщения. Тогда воркер, не получив контекст, стартует новую трассу — и путь рвётся. Лечится инструментацией продюсера (записать trace-context в сообщение) и консьюмера (извлечь и продолжить трассу). Это типичная слепая зона на асинхронных границах.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.