Яндекс.
Маркет имеет большую микросервисную архитектуру.
Запрос браузера на главной странице Маркета генерирует десятки вложенных запросов к различным сервисам (бэкендам), которые разрабатываются разными людьми.
В такой системе может быть сложно точно понять, почему запрос упал или обработка заняла много времени.
Анатолий Островский мегатоля объясняет, как его команда решила эту проблему, и делится практиками, специфичными для Маркета, но в целом актуальными для любого крупного сервиса.
Его отчет основан на собственном опыте развертывания нового маркетплейса за достаточно короткое время.
Толя несколько лет возглавлял команду разработки интерфейсов в «Маркете», а сейчас перешел в направление беспилотных автомобилей.
— Все наши маркетплейсы построены по общим принципам.
Это одна большая единая система.
Но если говорить о фронтенде, то с точки зрения пользователя приложения совершенно разные.
В то же время наши интерфейсы подключаются ко многим бэкэндам.
Иногда эти бэкэнды похожи друг на друга (разные экземпляры одного и того же приложения).
А иногда они уникальны для данной услуги (специальный биллинг).
Структуру такой системы можно считать классической микросервисной архитектурой.
В большом сервисе всегда есть проблема — сложно понять, что именно в нем сейчас происходит. Или, например, что происходит в тот момент, когда происходит ошибка платежа пользователя.
Допустим, это случилось с ним вчера, и сегодня нам нужно понять, что произошло.
Backend 2 может быть «включен» либо для конкретного продукта, либо в определенное время, либо для конкретных пользователей.
Мы должны уметь реагировать на любую ситуацию.
У нас много бэкендов, и, как я уже сказал, они могут уходить в себя.
Если представить это в виде графика, то получится довольно запутанно.
В реальной жизни микросервисов могут быть сотни.
Представьте, сколько связей будет между ними.
В этой теме есть много уровней погружения.
Кратко расскажу о каждом из них.
Прежде всего договоритесь с коллегами по бэкенду об общей системе маркировки запросов — так их будет легче найти в дальнейшем.
Далее нужно уметь быстро воспроизводить проблемы.
Допустим, произошла ошибка платежа — постарайтесь быстро понять, как это произошло и в каком бэкенде.
Храните журналы не только в файлах, но и в базе данных, чтобы можно было выполнять агрегирование.
И, конечно же, важная часть процесса — графики и мониторинг.
Далее обо всем по порядку.
Единая система идентификации запросов
Это один из самых простых инструментов для понимания того, что сейчас происходит с сервисом.
Договоритесь с коллегами, что, например, ваш фронтенд генерирует какой-то id-запрос (переменная requestId на картинке), а затем отправляет его всем бэкенд-эндопоинтам.
А сам бэкэнд ничего не изобретает заново.
Он принимает входящий идентификатор запроса и пересылает его дальше в запросах к своим бэкэндам.
При этом он может указать свой префикс, чтобы именно этот бэкенд можно было найти среди одинаковых requestIds.
Таким образом, когда вы собираете свои логи, убеждаясь, что в них написано, например, что бэкенд пятьсот, может быть два варианта.
Вы либо дадите этот идентификатор запроса своим коллегам, и они просмотрят его в своих журналах, либо вы посмотрите его самостоятельно.
Все наши логи помечены такими идентификаторами, чтобы не только понять, что произошло и в какой момент, но и сохранить контекст этого запроса.
Он асинхронный, поэтому вы можете добавить что-нибудь в журнал позже.
А если схватиться по requestId, то ничего хорошего из этого не выйдет.
КУЛЬ
Для воспроизведения проблемы воспользуемся утилитой cURL. Это консольная утилита, которая делает сетевые запросы — http и https. cURL поддерживает гораздо больше протоколов, но при веб-разработке его проще рассматривать как инструмент для работы с http(s)-запросами.
Чтобы познакомиться с командой cURL, вы можете зайти на любой сайт, затем зайти в Сеть и скопировать любой запрос как cURL. Вы получаете эту большую строку:
Если попытаться разобраться, ничего страшного здесь нет. Попробуем разобрать его по частям.
Вот запрос на сайт market.yandex.ru.
Сюда добавлен User-Agent, который и так занимает много места.
Фактически, остальное пространство занимают файлы cookie. Их в коде Яндекса довольно много.
В сериализованном виде они имеют весьма угрожающий вид. На самом деле, кроме них здесь больше ничего нет. Так чем же полезен cURL? Если бы вы скопировали его себе и запустили, то увидели бы ту же страницу market.yandex.ru, что и я - только компьютер, на котором он был запущен, был бы другой.
Конечно, различия в IP-адресах могут иметь некоторые побочные эффекты, но в целом это будут одни и те же запросы.
Мы с вами воспроизведем один и тот же сценарий.
Чтобы не придумывать себе каждый раз такие cURL-запросы, можно использовать npm-пакет format-curl.
Он принимает все параметры запроса, которые обычно принимает функция — то есть в данном случае только заголовки и URL. Но он также может запрашивать, тело и т. д. И на выходе получается просто строка с запросом cURL.
Поэтому все наши логи в среде разработки также содержат запросы cURL.
Мы даже логгировали бэкенд-запросы cURL прямо в браузере, чтобы сразу видеть, как мы заходим на наши бэкенды, не глядя на консоль браузера.
Обратите внимание, что запросы cURL предполагают передачу сессионных куки — это плохо.
Если бы вы отправили мне свой cURL-запрос на market.yandex.ru, то я мог бы войти в Маркет и любой другой сервис Яндекса, используя ваш логин.
Поэтому мы такие запросы нигде не храним, а логируем их только в тестовых стендах для себя — такие данные не могут быть утешены.
Кликхаус
Далее я расскажу о структурированных журналах.Здесь я буду иметь в виду конкретную базу данных ClickHouse, но вы можете выбрать любую.
ClickHouse — столбчатая СУБД; удобнее выбирать из огромного количества данных и принимать большие фрагменты данных.
Он хорош тем, что в нем можно сохранить большой кусок журнала и потом, например, сделать какую-то агрегацию по миллиарду записей.
В данном случае примером выбора ClickHouse является обычный SQL. Здесь мы показываем количество запросов кодов состояния за сегодняшний день.
В итоге у нас будет 180 тысяч двести семь пятьсот, а остальные коды статусов нам, например, не интересны.
Но как мы можем использовать это интересным образом?
Можно сказать, что отношение двухсот к отношению общего количества ответов и есть Индикатор уровня обслуживания, который отвечает на вопрос, насколько хорошо работает наше приложение с точки зрения кодов состояния.
Хоть это и просто, но уже о чем-то говорит.
На основе нашего индикатора мы можем прийти к первому SLI, то есть, скажем, например, что 99% наших запросов должны быть ОК.
И вот тут мы можем сравнить, что мы доделали наш SLI. Если бы они этого не выполнили, то могли бы попытаться разобраться либо в каких-то недавних запросах, которые дошли бы до пятисот, либо просто в критических вещах.
Например, для нас критичны ошибки оплаты, но в этом случае они вернут ноль — повезло :)
Как вы можете гарантировать, что ваши логи хранятся в такой удобной форме и их можно получить через SQL?
Это тема для отдельного большого доклада, и тут все сильно зависит от вашей инфраструктуры.
Но здесь, кажется, есть два пути.
Первый: отправьте метаданные непосредственно во время выполнения, непосредственно в базу данных.
Мы делаем по-другому, вторым способом: отслеживаем лог-файл и передаем частями либо в базу данных, либо в промежуточное место.
У нас это работает довольно многоуровнево — мы отправляем логи с конкретного экземпляра на удаленный сервер, на котором такие логи хранятся.
Запросить отслеживание
Понятия «отслеживание запросов» не существует. Этот термин был придуман Google.Если вы выполните поиск в Интернете по запросу «отслеживание запросов», вы встретите команду трассировки.
Возможно, это похоже на отслеживание запросов.
Есть даже консольная программа, и здесь я реализовал ее для сайта Bringly.ru (сервис, который мы разработали прошлой весной).
Это помогает понять, через какие машины и серверы проходит запрос, прежде чем попасть на балансировщик, который ответит либо макетом, либо чем-то еще.
Вот наш балансир.
Под трассировкой запросов мы подразумеваем не это, а все, что происходит внутри нашего балансировщика — как запрос живет внутри нашего приложения node.js.
Мы видим это в виде временной шкалы, где время отображается горизонтально, а порядок запросов — вертикально.
В данном случае у нас есть запрос к карточке товара, где мы видим, что это запрос к бэкенду нашей авторизации.
После его решения было отправлено три длинные строки — это запрос к нашему основному бэкенду на корзину, карточку товара и тому подобные товары.
Вот как выглядит наша трассировка.
Здесь вы можете увидеть тот же запрос на авторизацию, а затем пошел бэкенд. В этом случае бэкенд ведет себя не очень оптимально, поскольку у него много последовательных запросов к его базе данных.
Вероятно, этот запрос можно оптимизировать.
А вот пример трассировки, когда мы не зашли ни в какой бэкенд, а сразу выдали статус 500. Чем нам полезна такая трассировка? Нам не придется беспокоить наших коллег.
У нас есть id этого запроса, поэтому мы можем сами посмотреть логи и разобраться, что происходит.
Здесь ситуация противоположная.
Бекенд сказал, что что-то не так и при этом написал в метаинформации, что именно произошло — появился какой-то стек-трейс.
Как сделать такой же инструмент для себя?
Самое главное здесь — это база данных.
Если у вас есть простейшее «INSERT INTO» в базе данных каких-то действий с сервисом, то позже вы сможете хотя бы найти нужные события с помощью SQL. И при необходимости для этого можно сделать интерфейс.
Графики
Это очень интересная тема, подробно останавливаться на ней сегодня я, конечно, не буду :)Давайте поговорим о логировании.
Графиков у нас много, мы на них смотрим, когда что-то выкатываем — а там такой шум в таймингах.
Графики помогают визуально увидеть, что что-то не так.
А потом еще надо посмотреть логи и понять по ним, что именно не так.
В данном случае всплеск сразу после релиза как минимум означает, что такой релиз нужно немедленно откатить.
Мониторинг
Еще более важная часть и более сильная степень погружения в эту тему — мониторинг.Под мониторингом я подразумеваю, во-первых, автоматический мониторинг графиков и, во-вторых, любые автоматизированные правила мониторинга чего-либо.
Мы следим за соотношением пятисот к общему количеству ответов в минуту.
Также отслеживаем четыре сотни, наличие нагрузки на сервис, проверку хэндла проверки работоспособности, который тянет пинг-хэндл каждого из бэкендов и т.д.
Кроме того, у нас есть панели мониторинга, которые мы отображаем на экранах рядом с рабочими станциями.
Таким образом, мы можем сразу увидеть, какая из систем мониторинга горит красным.
Например, вот он один из основных, где виден фронтенд и наш основной бэкенд. Здесь вы можете видеть, что на серверной части горят индикаторы мониторинга.
Это означает, что в этот момент ответственный за этот сервис человек получит сообщение в Telegram, а возможно, ему даже позвонят — это зависит от настроек мониторинга.
Полученные результаты
Единый requestId поможет вам легче находить проблемы в сервисе, состоящем из нескольких приложений.Правильный cURL позволит более точно воспроизвести проблемы и увидеть, как вы сами, например, отправляете данные на бэкенд. Структурированные журналы позволят создавать SLI, и их удобнее использовать, чем обычные текстовые журналы.
И не забывайте следить за графиком и вести мониторинг.
Я рекомендую прочитать это книга Проектирование надежности сайтов от Google, если вас интересуют вопросы инфраструктуры.
Теги: #Разработка сайтов #Микросервисы #мониторинг #логирование #интерфейсы #Промышленное программирование #clickhouse #curl #запросы #трассировка #команда Яндекс.
маркета
-
Заправки Чернил Для Принтера
19 Oct, 24 -
Разочарования И Проблемы С Предложениями
19 Oct, 24 -
Clojurescript — Изменение Кода На Лету
19 Oct, 24 -
Система Озвучки Для Игр (С Плагином Unity)
19 Oct, 24 -
Лепестки Роз На Вечеринке
19 Oct, 24