Ответ
Да, я активно использовал стек инструментов для обеспечения наблюдаемости (observability) микросервисов, который строится на трех основных столпах: метрики, логи и трассировки.
1. Метрики (Monitoring)
Для сбора и анализа метрик я использовал связку Prometheus + Grafana.
- Prometheus: Это система для сбора и хранения временных рядов (time-series). В Go-приложение легко интегрируется клиентская библиотека
prometheus/client_golang. Я экспортировал стандартные метрики (CPU, память, Go runtime) и кастомные бизнес-метрики (например, количество обработанных запросов, время выполнения операций, количество ошибок — так называемый RED-метод: Rate, Errors, Duration). - Grafana: Инструмент для визуализации данных из Prometheus в виде дашбордов.
Пример экспорта кастомной метрики:
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var httpRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path"}, // Метка для разделения по методу и пути
)
func myHandler(w http.ResponseWriter, r *http.Request) {
httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path).Inc()
w.Write([]byte("Hello, World!"))
}
func main() {
http.HandleFunc("/", myHandler)
http.Handle("/metrics", promhttp.Handler()) // Эндпоинт для сбора метрик
http.ListenAndServe(":8080", nil)
}
2. Логирование (Logging)
Для логирования я предпочитаю использовать структурированные логи в формате JSON. Это позволяет легко парсить, индексировать и искать логи в системах вроде ELK Stack (Elasticsearch, Logstash, Kibana) или Loki.
- Библиотеки в Go:
zerologилиzap. Они очень производительные и удобные для создания структурированных логов. - Системы сбора: Loki от Grafana Labs — легковесная альтернатива ELK, хорошо интегрируется с Prometheus и Grafana.
3. Трассировка (Tracing)
Для отслеживания запросов в распределенной системе я использовал OpenTelemetry как стандарт для инструментирования кода и Jaeger в качестве бэкенда для хранения и визуализации трейсов.
- OpenTelemetry (OTel): Позволяет добавлять в код информацию о
span-ах (этапах выполнения запроса) и передавать контекст трассировки между сервисами через HTTP-заголовки или метаданные сообщений. - Jaeger: Помогает визуализировать полный путь запроса через все микросервисы, находить узкие места и анализировать ошибки в сложных взаимодействиях.
4. Профилирование (Profiling)
Для глубокого анализа производительности я использовал встроенный в Go инструмент pprof. Он позволяет собирать профили CPU, памяти (heap), горутин и блокировок, чтобы находить и устранять проблемы производительности непосредственно в коде.
Ответ 18+ 🔞
А, наблюдаемость, говоришь? Ну, это ж святое, когда у тебя этих микросервисов, как тараканов за печкой, овердохуища! Если за всем этим зоопарком не следить — пиши пропало, через неделю уже не поймёшь, какой из них тебе в тихую всю память сожрал или в бесконечный цикл ушёл.
Короче, я эту магию строил на трёх китах, как и полагается: метрики, логи и трассировки. Без этого — ты просто слепой крот в подземном лабиринте, блядь.
1. Метрики (Твои цифровые стукачи)
Тут мой выбор — связка Prometheus + Grafana. Просто, как три копейки, и работает, как швейцарские часы, если, конечно, не накосячить.
- Prometheus — это такой занудный бухгалтер, который только и делает, что сидит и постоянно пересчитывает все твои цифры: сколько запросов, сколько времени, сколько ошибок. В Go втыкаешь библиотечку
prometheus/client_golang— и понеслась. - Grafana — это уже для начальства. Берёт все эти скучные цифры от бухгалтера и рисует красивые картинки, графики и дашборды, чтобы даже менеджер мог понять, что всё «охуенно зелёное» или «пиздец как красное».
Вот, смотри, как я, например, счетчик запросов на коленке делал:
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Создаём счётчик, который будет считать запросы по методу и пути
var httpRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total", // Имя, как в паспорте
Help: "Total number of HTTP requests", // Пояснение для чайников
},
[]string{"method", "path"}, // Разделяем, кто есть кто
)
func myHandler(w http.ResponseWriter, r *http.Request) {
// Пришёл запрос — чик, увеличили счётчик
httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path).Inc()
w.Write([]byte("Hello, World!"))
}
func main() {
http.HandleFunc("/", myHandler)
// Вот этот волшебный эндпоинт, куда Prometheus будет приходить как голодный студент в столовую
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}
И вот уже Prometheus тыкается в твой /metrics, считывает эти цифры, а ты в Grafana смотришь, какой эндпоинт у тебя самый популярный — может, его уже пора в отдельный сервис выносить, пока он всё не обоссал.
2. Логи (История болезни каждого сервиса)
А вот логировать просто в текстовый файл — это уровень пещерного человека, ей-богу. Сейчас в моде структурированные логи, в идеале — в JSON. Почему? Да потому что потом их машине легче жрать!
- Библиотеки: В Go я уважаю
zerologилиzap. Быстрые, не грузят приложение, и ты можешь к каждому сообщению прилепить кучу полей:user_id,transaction_id,error_code. Не то что эти вашиprintfс кучей текста. - Куда складывать: Раньше все тащили в ELK Stack (Elasticsearch, Logstash, Kibana) — мощно, но для него свой отдельный кластер порой нужен. Сейчас модно использовать Loki от Grafana. Он как Prometheus, только для логов. Легковесный, и логи сразу рядом с метриками в Grafana можно смотреть — красота!
3. Трассировка (Детектив следователь)
Ну а это самый крутой уровень, когда тебе нужно проследить один-единственный запрос пользователя, который прошарился через пять разных сервисов, в каждом по два раза побывал, и в итоге вернулся с ошибкой 500. Без трассировки ты будешь как тот Герасим из рассказа — только «Муму» мычать и не понять, где же именно пиздец случился.
- OpenTelemetry (OTel) — это сейчас стандарт де-факто. Ты инструментируешь код: отмечаешь начала и концы операций (спаны), а OTel аккуратно протаскивает идентификатор трассировки через все сервисы, будь то HTTP или очередь сообщений.
- Jaeger — это следователь, который все эти спаны собирает и показывает тебе на красивом дереве весь путь запроса. Видно сразу: ага, этот сервис отработал за 5 мс, а этот — за 5 секунд, потому что десять раз сходил в базу, идиот. Находишь узкое место — и тут уже можно с профилированием разбираться.
4. Профилирование (Вскрытие покажет)
А вот когда метрики показали, что CPU ушёл в даун, а логи молчат, — тут в бой идёт тяжёлая артиллерия. В Go для этого есть встроенный pprof. Это как рентген для твоего приложения.
Поднимаешь специальный эндпоинт, подключаешься к нему — и можешь снять снимок:
- Профиль CPU — покажет, какая функция твою процессорную мощь пожирает.
- Профиль памяти (heap) — выявит, кто там память не отпускает и устраивает утечку.
- Профиль горутин — найдет тех, кто уснул и забыл проснуться, создавая утечку.
В общем, наблюдаемость — это не роскошь, а средство выживания в мире микросервисов. Без этого ты просто на ощупь в тёмной комнате ищешь чёрную кошку, которой там, вполне возможно, уже давно нет. А с этим — у тебя полная картина, тепловизор и датчики движения на каждый чих. Живи спокойно. Ну, почти.