Примечание от нашей редакции переводов: в представляемой статье описывается закрытый продукт конкретной компании и, к сожалению, пока нет никаких данных о том, что его когда-либо планируют открывать — в столлмановском понимании этого слова. Тем не менее, нам показалось очень важным и полезным рассмотреть, как вообще люди подходят к вопросам дебага Istio и как оптимизируют свою работу на этом поле. Возможно, кто-то сможет почерпнуть для себя пару интересных идей.
В какой-то момент, при разработке продакшн-систем на основе микросервисной архитектуры мы пришли к тому, что мониторинга каждого отдельного элемента нашего сервиса недостаточно, чтобы справляться с серьезными проблемами. С течением времени назрела необходимость получать полную картину всего стека вызовов во всем приложении одновременно, причем с подробной информацией о топологии запросов, задержках сети и длительности отдельных команд. Обычно для решения подобной задачи инженеры прибегают к распределенной трассировке.
В этом посте концепция распределенной трассировки будет рассмотрена через призму микросервисной архитектуры: как это все интегрируется и автоматизируется через Istio, а затем весь процесс упрощается и обрабатывается через Backyards — наш сервисный продукт для Istio.
Вступление
Ранее мы писали о том, насколько сложной может быть просто установка и настройка Istio, поэтому для упрощения этой ситуации мы выбрали open source-разработку Banzai Cloud Istio. Помимо Istio, вы можете использовать с Helm целый ряд удобных инструментов (Prometheus, Grafana, Jaeger, Kiali), во всяком случае, большинство запросов на поддержку/интеграцию поступали именно по ним. Так как мы считаем, что каждый выбирает себе инструмент по вкусу, то не стали жестко внедрять перечисленный инструментарий в Istio, а лишь обеспечили возможность легко интегрировать эти компоненты.
Кроме того, мы хотели предоставить нашим пользователям еще один мощный инструмент для управления перечисленными компонентами в кластере (то есть что-то кроме Istio), так что мы создали еще и Backyards. С его помощью можно легко установить Prometheus, Grafana и Jaeger, и, в отличие от Kiali, Backyards — это не просто веб-интерфейс для мониторинга, а полноценный многофункциональный инструмент управления сетью ваших сервисов. Он совместим с одним или сразу несколькими кластерами и содержит мощный CLI и GraphQL API.
В этом посте мы сосредоточимся на распределенной трассировке и Jaeger.
Введение в распределенную трассировку
В архитектуре микросервисов, когда несколько сервисов одновременно вызывают друг друга, часто бывает непросто заниматься поиском и отладкой проблем. Собственно, в этом утверждении и кроется основная причина, по которой эффективность запросов к сервисам низкая: какая служба стала узким местом, насколько велика задержка сети между запросами?
Благодаря распределенной трассировке можно визуализировать полное древо вызовов, посмотреть, какая служба обратилась к какой службе, сколько времени занимает каждый вызов и какова задержка ответа. Именно распределенная трассировка помогает определить, где произошел сбой и какая служба вышла за лимит времени на ответ.
Распределенная трассировка — это процесс отслеживания отдельных запросов по всему стеку вызовов внутри системы.
Не используя распределенную трассировку, действительно, легко потеряться в многочисленных вызовах, которыми обмениваются между собой микросервисы. Также без нее сложно заниматься отладкой проблем, так как приходиться опираться только на логи. Но благодаря распределенной трассировке вам становится доступен весь стек вызовов со всей необходимой для диагностики проблемы информацией.
Под капотом распределенной трассировки
Span — это наименьшая единица в распределенной трассировке. У нее есть метки «начало» и «длительность». Span между собой имеют материнско-дочерние связи и вместе образуют Trace.
Есть три задачи, в рамках которых корректно собирать трассировки
1. Incoming request spans
2. Outgoing request spans
3. Context propagation
Incoming request spans:
когда запрос поступает в службу, его необходимо проверить на наличие заголовка трассировки. Если заголовка нет, то необходимо создать корневой (материнский) span для начала трассировки, если есть — создать дочерний span для продолжения трассировки.
Outgoing request spans:
когда запрос отправляется из одной службы в другую, сначала создается span, благодаря чему принимающая запрос сторона продолжает трассировку, как описано выше.
Context propagation:
обычно службы получают и отправляют несколько запросов одновременно. Без внесения каких-либо изменений отследить связь между входящими и исходящими запросами невозможно. Вот тут и наступает звездный час для передачи контекста. Для HTTP это можно сделать через передачу заголовков трассировки входящих вызовов к исходящим из приложения, что позволит построить полную трассировку.
Помимо этих задач, трассировки должны быть собраны, сгруппированы и идеально визуализированы.
Все это может показаться достаточно сложным для реализации на всех службах внутри системы, но существуют инструменты, которые позволяют решать почти все описанные задачи в автоматическом режиме. В итоге разработчики могут получать распределенную трассировку, фактически, из коробки.
Для получения большего количества информации об основных принципах распределенной трассировки я бы порекомендовал к прочтению этот замечательный пост от Nike.
Распределенная трассировка в Istio
В Istio грязную работу по распределенной трассировке выполняют прокси-серверы Envoy. В Istio наличествует sidecar-инъекция, благодаря которой все входящие и исходящие запросы к/от сервиса сначала проходят через прокси-сервер Envoy. Именно на этом этапе генерируются материнские и дочерние трассы, которые являются первыми двумя из трех необходимых условий создания распределенной трассировки.
Третье условие — передача контекста — должно выполняться через изменение логики приложения. В Istio Bookinfo это уже реализовано на уровне каждого микросервиса, поэтому полные трассировки можно получить сразу же после установки. При использовании распределенной трассировки в своих собственных сервисах вам необходимо реализовать context propagation самостоятельно.
Вопреки некоторым распространенным заблуждениям стоит заметить, что полная поддержка распределенной трассировки с context propagation даже на уровне обычной сервисной сетки может быть создана только путем изменения логики работы приложения. Хороший пример приводится в Caveat 1.
На сайте Istio лежит документация о том, какие заголовки (хедеры) нужно использовать. Все они совместимы с форматом заголовков Zipkin.
Обратите внимание, что, помимо описанной выше трассировки на основе Envoy, в Istio есть Mixer-based трассировка, которая активнее использует компонент Mixer. Вероятно, в последующих версиях поддержка Mixer будет прекращена, поэтому подробно работу с ним я описывать не буду. Стоит лишь сказать, что mixer-телеметрию можно пощупать через оператора.
С помощью Envoy и распространения нужных нам заголовков трассировки мы можем получить необходимые нам трассы. Для сбора и визуализации этой информации Istio поставляется с такими инструментами, как Jaeger, Zipkin, Lightstep и Datadog. По умолчанию используется Jaeger, он же и самый популярный инструмент из всех перечисленных.
Также мы можем настроить частоту дискретизации, то есть то, какой процент от всех запросов будет представлен в виде трасс. По умолчанию используется значение в 1% от общего числа запросов. Частоту можно изменить вот в этом поле оператора Istio.
Как это работает в Istio
Давайте подведем итог того, как делать распределенную трассировку с помощью Jaeger (позже мы сравним это с тем же процессом в Backyards):
1. Вместе с Istio вы получаете Jaeger со всеми необходимыми сервисами и деплоем.
2. Адрес службы трассировки задается по умолчанию по конфигурации прокси-серверов Envoy и через них идут репорты Span и работают sidecar-сервисы.
3. Bookinfo может быть установлена до того, как все сервисы распределят свои head-заголовки на traces.
4. Traces станут доступны после того, как будет собрано достаточно информации.
5. Панель управления Jaeger может быть перенаправлена для открытия пользовательской части через браузер.
Распределенная трассировка в Backyards
В Backyards установка, настройка Jaeger, инсталляция демо-приложения с автоматически распространяемыми заголовками трасс и отправка на все это нагрузки — все выполняется с помощью одной простой команды! А после линкования сервисов между собой трассами все это становится доступно из пользовательского интерфейса.
А теперь смотрите!
Создаем кластер
Ну, для начала нам потребуется кластер в Kubernetes. Я поднял кластер Kubernetes на GKE через бесплатную версию Pipeline для разработчиков. Если хотите сделать тоже самое, то создайте свой кластер через Pipeline на любом из пяти поддерживаемых нами облачных провайдеров. В противном случае поднимите свой кластер Kubernetes где-нибудь еще.
Как это работает в Backyards
Ранее мы подвели промежуточный итог, что Jaeger можно использовать в связке с Istio. Теперь сравним, как все происходит в Backyards.
Сейчас самый простой способ установить Istio, Backyards и демо-приложение на новый кластер — это использовать интерфейс командной строки Backyards.
Вам нужно ввести только одну команду (на вашем кластере должен быть
KUBECONFIG):
$backyards install –a –run-demo
1. С помощью этой команды автоматически устанавливается Jaeger (вместо с нашим open source-оператором Istio и компонентами Backyards).
2. Как упоминалось ранее, Istio из коробки готов к интеграции с другими компонентами, например Prometheus, Grafana или Jaeger. Когда Jaeger установлен, адрес его службы задается в пользовательском окне оператора. В дальнейшем этот адрес прописывается в каждом месте, где он нужен для управления компонентами Istio и потоком данных.
3. Demo-приложение также устанавливается по умолчанию. Оно использует сервисы golang, которые уже настроены для распространения необходимых заголовков трассировки.
4. Начинается автоматическая загрузка demo-приложения (отсюда и флаг --run-demo), так что можно сразу начать отслеживать трассы.
5. Jaeger открывается через входной шлюз, он залинкован с UI и автоматически доступен как в виде схемы, так и в виде списка.
Это буквально также просто, как и написать команду создания нового кластера Kubernetes, так что если хотите — попробуйте!
Вот что вы увидите:
Jaeger, залинкованный со схемой:
А тут уже в виде списка:
UI Jaeger для demo-приложения:
В UI вы можете увидеть весь стек вызовов в вашей системе микросервисов. Теперь вы можете отследить, когда именно был запущен root-запрос и сколько времени занял каждый реквест. Или, например, вы можете увидеть, что аналитическая служба большую часть времени потратила какие-то определенные запросы, так как занята фактическими вычислениями (например, вычисляет значения числа Пи).
Очистка
Чтобы удалить demo-приложение, Backyards и Istio из вашего кластера, вам нужна только одна команда. Она позаботится об удалении всех компонентов в правильном порядке:
$ backyards uninstall -a
Итоги
Распределенная трассировка необходима, в основном, для действующих распределенных систем, в которых нужно устранять какие-либо сложности или проблемы. Наш оператор Istio сконцентрирован исключительно на управлении, когда как Backyards содержит намного больше компонентов, которые можно использовать в работе. Например — это Jaeger, который из коробки обеспечивает возможность проведения распределенной трассировки.
При этом Jaeger устанавливается с помощью Backyards, а последний отображает все ссылки и следы Jaeger в системе прямо в интерфейсе!
Удачной трассировки!
Автор: ITSumma