Программы
MessageId или как дебажить систему с минимумом проблем

MessageId или как дебажить систему с минимумом проблем

В современном мире микросервисов и прочих SOA обработка запроса может быть распределена на десятки сервисов. К каким проблемам это приводит при отладке и исследовании, как уменьшить накладные расходы на поиск "одной строчкой"?

Часто случается, что клиент не доволен результатом работы вашего сервиса. Иногда это оправдано, иногда это странные фантазии клиента. Но нам важно понимать: запрос реально сделал что-то не то, или же клиент это воспринимает не так, как мы ожидаем. Также бывают более сложные ситуации. Мы знаем, что произошла ошибка, но не можем понять: где и из-за чего?

Предположим, что мы грамотно сделали систему логирования. Используем ELK (elastic + logstash + kibana). Но как найти нужный запрос среди кучи непонятных сообщений? Особенно, если система разбита на части между микросервисами.

Тут нам на помощь приходит MessageId или RequestId - идентификатор запроса к сервису. Это должен быть уникальный идентификатор каждого запроса к сервису. И его мы будем тащить от одного сервиса к другому всегда. Вот просто добавьте во все свои контракты MessageId или message_id - пофиг. Главное всюду и всегда. А самое главное - во всех логах:

  • Есть обращение к ресурсу - указали MessageId.
  • Не нашёлся ресурс - MessageId.
  • Сервис решил упокоиться с ООМ - MessageId записал!

Что нам даёт MessageId

В современном мире для хранения логов используются специализированные средства. Нет необходимости grep-ом парсить гигабайты данных - сейчас терабайты лежат в ELK. И реально сложной задачей было бы парсить логи на десятке различных нод, десятков сервисов... Куда проще централизовать логи, и центрально ими же манипулировать.

Возьмём ту же Kibana. Захотели мы глянуть: какие ошибки бывают - "logger.level: ERROR" - видим, если красиво настроили логгер, какие сообщения летят с ошибкой. При том агрегировано по инстансам/головам/контейнерам/виртуалкам/подам - не знаю, как вы это называете.

Теперь, если есть по кому-то проблема, как найти источник? Посмотреть логи вглубь от начальной ноды до проблемной. Как это сделать? Было бы прикольно иметь какой-то идентификатор, по которому можно найти все действия по какому-то сообщению (message) пользователя, то есть его запросу (request). Думаю, вы поняли "MessageId" и "RequestId" - словообразование очевидное.

И если мы проносим этот идентификатор всюду, мы сможем в логах указать (обычно это автоматизировано библиотеками), к какому запросу относится тот или иной лог. И что более полезно - по "message_id: 123321" увидеть весь путь запроса!

Кто ставит message_id / откуда идентификатор

Есть несколько подходов:

  • пусть клиент выставляет,
  • система внутри выдумывает,
  • по запросу генерится и прочие.

Если мы допускаем, что клиент сам гененрит, мы должны верить в то, что он не сделает дублей, либо проверять на это (а это дорого). Допустимый вариант - если мы доверяем клиенту.

Если мы сами хотим генерировать message_id, то мы должны сильно озаботиться обратной связью с пользователем. Иначе, как он просигнализирует, где возникла проблема. То есть в любом ответе, даже об ошибке, должен лежать идентификатор сообщения. И любой ответ должен быть доставлен...

Гибридные варианты сложны. Обычно сочетается наличие и отсутствие message_id. Если есть - используем, если нет - сами пришлём. Довольно неплохой вариант. К сожалению или счастью, я более радикален - не прислали message_id = HTTP 422 - плохая сущность... В виде гномика...

Итоги: нужен ли MessageID

Если у вас монолитное приложение при определённых условиях, вам не нужно всё это. Если вы не логируете - вам тоже эта инфа пока не нужна (до первого серьёзного сбоя). Все остальные - если ещё не трекаете запросы через message_id - начинайте! А то будет жопа...