Ответ
Отладка межсервисного взаимодействия — это комплексная задача, требующая разных подходов на разных этапах. Я бы разделил эти подходы на несколько уровней:
1. Локальная разработка и тестирование
На этом этапе цель — быстро проверить логику и найти ошибки до развертывания.
-
Структурированное логирование: Вместо простого
log.Printfя использую структурированные логгеры (например,slogиз стандартной библиотеки,zerolog,zap). Это позволяет добавлять контекст (ID запроса, имя сервиса) и легко фильтровать логи.// Пример с slog logger.Info( "sending request to service", "service", "auth-service", "url", url, "request_id", reqID, ) -
Дампинг HTTP-запросов/ответов: Для детального анализа сетевого взаимодействия можно использовать
httputil.import "net/http/httputil" // Дамп исходящего запроса reqDump, err := httputil.DumpRequestOut(req, true) log.Printf("REQUEST:n%s", string(reqDump)) // Дамп входящего ответа respDump, err := httputil.DumpResponse(resp, true) log.Printf("RESPONSE:n%s", string(respDump)) -
Mock-серверы: В unit- и интеграционных тестах я использую
httptest.NewServerдля имитации ответов от внешних сервисов. Это позволяет тестировать мой сервис в изоляции. -
Пошаговая отладка (Debugger): Использую отладчик Delve для прохождения по коду шаг за шагом, анализа переменных и стека вызовов.
2. Анализ на тестовых/staging стендах
Здесь сервисы работают в окружении, близком к production.
-
Распределенная трассировка (Distributed Tracing): Это ключевой инструмент. Он позволяет отследить жизненный цикл одного запроса через несколько сервисов. Я использую OpenTelemetry для инструментирования кода, а в качестве бэкенда для сбора и визуализации трейсов — Jaeger или Zipkin.
-
Анализ сетевого трафика: Инструменты вроде Wireshark или tcpdump для глубокого анализа пакетов, если есть подозрения на проблемы на сетевом уровне.
-
Инструменты для тестирования API: Postman, Insomnia или grpcurl (для gRPC) для ручной отправки запросов и проверки ответов от развернутых сервисов.
3. Наблюдаемость (Observability) в Production
В production прямое вмешательство невозможно, поэтому мы полагаемся на "три столпа наблюдаемости":
- Логи: Агрегированные и индексируемые логи (например, в стеке ELK/EFK или Loki), которые можно централизованно искать и анализировать.
- Метрики: Сбор ключевых показателей работы сервиса (время ответа, количество ошибок, использование ресурсов) с помощью Prometheus и их визуализация в Grafana.
- Трейсы: Распределенная трассировка, как и на staging, помогает находить узкие места и ошибки в цепочках вызовов.
Ответ 18+ 🔞
Ну вот, опять про эту вашу распределённую хуетень, где один сервис у другого в жопу просит, а тот третьему, а третий четвёртому, и в итоге ответ как в известном анекдоте — хуй с горы, а не то, что ожидалось.
Слушай, давай по полочкам разложу, как я с этим бедламом борюсь, а то у меня уже терпения ноль ебать от этих микросервисов.
Первый этап: когда ты ещё на своей машине и можешь всё сломать
Тут главное — не пиздеть в лог абы как. Забудь про log.Printf("тут что-то не так"). Это пиздопроебибна уровня «ой, всё». Бери структурированный логгер, хоть новый slog, и пихай в каждое сообщение контекст. Чтобы потом, когда всё ебнется, ты мог найти все записи по одному request_id, а не гадать, какая из миллиона строчек «тут что-то не так» относится к твоей проблеме.
logger.Info(
"сейчас буду ебашить в соседний сервис",
"service", "auth-service",
"url", url,
"request_id", reqID, // Вот эта хуйня — твой спасательный круг!
)
А если совсем припёрло и непонятно, что летит по сети, дампи запросы и ответы. Это как подслушать, о чём два сервиса шепчутся.
import "net/http/httputil"
// Что я отсылаю
reqDump, _ := httputil.DumpRequestOut(req, true)
log.Printf("МОЙ ЗАПРОС:n%s", string(reqDump))
// Что мне прилетает в ответ
respDump, _ := httputil.DumpResponse(resp, true)
log.Printf("ЕГО ОТВЕТ:n%s", string(respDump))
И, конечно, дебаггер. Запускай Delve и проходи по шагам. Иногда только так понимаешь, что переменная nil не потому, что сервис сдох, а потому что ты, мудак, её не инициализировал.
Второй этап: когда всё уже на тестовом стенде и начинает по-настоящему ебаться
Тут уже логи с трёх машин, и понять, где начало цепочки, — это пиздец. На помощь приходит распределённая трассировка. Ставишь OpenTelemetry, цепляешь Jaeger — и вуаля, видишь весь путь одного запроса, как на ладони. Видишь, что сервис А отработал за 5 мс, а сервис Б тупил 5 секунд, потому что ждал ответа от сервиса В, который, блядь, просто уснул.
Если же подозреваешь, что проблема где-то в сетевой подкладке (пакеты теряются, как носки в стирке), то бери tcpdump или Wireshark. Это тяжёлая артиллерия, но иногда только так ловишь, как TCP-сессия резко обрывается на полуслове.
Третий этап: продакшен, где ты уже ничего не трогаешь руками
Тут, чувак, только наблюдаемость. Три кита, на которых всё держится, пока ты молишься, чтобы алёрты не сработали.
- Логи. Но не разбросанные по серверам, а сгребённые в одну кучу — в ELK, Loki или что у вас там. Чтобы по тому же
request_idнайти все следы. - Метрики. Prometheus + Grafana. Смотришь на графики: запросов много, а ответов мало? Лавина ошибок 5xx? Время ответа поползло вверх? Всё, блядь, начинается. Метрики — это твой радар, который засекает проблему раньше, чем пользователи начнут писать в саппорт.
- Трейсы. Та же трассировка, но в проде. Она помогает не просто найти сломанный сервис, а понять, где именно в цепочке он тормозит или падает. Без этого ты как слепой котёнок — тыкаешься во все стороны и надеешься на удачу.
Вот и вся магия. Сначала локально долбишь дебаггером и логами, потом на стенде включаешь трассировку и снифферы, а в проде только смотришь на графики и трейсы, и молишься, чтобы сегодня не пришлось всё это применять. А вообще, иногда кажется, что проще было на монолите писать, ёпта.