Секреты observability. Часть 1: метрики

от автора

image
Фото ETA+, Unsplash.com

Первые шаги в сторону observability — собираем метрики с Prometheus

Представьте себе человека, который бьется над решением загадки, а вокруг собралось с десяток советчиков, которые помогают ему «найти убийцу». Знакомая ситуация? В таких случаях возникает больше вопросов, чем ответов, и если отвечать на все эти вопросы, ни на что другое времени уже не останется.

Сложно найти то, чего не знаешь и не понимаешь. Вот тут-то на помощь и приходит observability (наблюдаемость). Она помогает понять, что сломалось или плохо работает, и даже позволяет найти причину, чтобы вы могли постоянно вносить улучшения.

Что такое observability

Под observability мы подразумеваем показатель того, насколько эффективно можно определить внутреннее состояние системы по ее выходным данным (телеметрии). Ничего нового в этом нет — мы пытаемся разобраться в работе приложений по логам с начала времен, но сейчас все осложняется облаками, контейнерами, микросервисами, многоязычными средами и т. д.

Три кита observability

Observability основана на трех главных компонентах. Это данные телеметрии, которые можно агрегировать и анализировать, чтобы понять состояние системы:

  1. Метрики.
  2. Трассировки.
  3. Логи.

В этой серии статей мы рассмотрим все три компонента с примерами. Начнем с метрик и опенсорс-проекта Prometheus.

Метрики

Метрика — это числовое значение за определенный период времени, например, счетчик, таймер или измеритель. Их сбор не требует много ресурсов, потому что числовые значения можно объединять, чтобы сэкономить на трафике. Обычно с помощью метрик мы определяем работоспособность системы, потому что они хорошо описывают статус ресурса. Кроме того, можно инструментировать код с помощью таких библиотек, как prometheus_client или prometheus_exporter, чтобы собирать кастомные метрики, например, время отклика, число активных запросов, количество ошибок и т. д.

Prometheus

Prometheus — это опенсорс-система мониторинга и оповещения на основе метрик. Изначально он был разработан SoundCloud, а теперь это проект Cloud Native Computing Foundation. Он собирает метрики об инфраструктуре и приложениях.
Prometheus состоит из нескольких компонентов:

  • Cервер Prometheus собирает метрики и хранит данные временных рядов.
  • Клиентские библиотеки генерируют метрики для приложения.
  • Push Gateway — промежуточный компонент, который позволяет пушить метрики из джобов, если скрейпинг невозможен.
  • Alert Manager обрабатывает алерты от Prometheus. Отвечает за группирование, дедупликацию и направление алертов нужному получателю.
  • Экспортеры собирают статистику из другой системы и преобразуют ее в метрики Prometheus.

image
Архитектура Prometheus

Деплоймент

Prometheus можно развернуть по-разному: установить в инфраструктуре вручную в контейнерах или Kubernetes или использовать helm — с оператором или без. Для простоты мы задеплоим Prometheus с помощью helm-чарта с оператором Prometheus.

kubectl create namespace observability helm repo add prometheus-community https://prometheus- community.github.io/helm-charts helm repo update helm install prometheus prometheus-community/kube-prometheus-stack -- namespace observability

На момент написания последняя версия Prometheus — 2.26, с удобными новыми фичами. Подробнее: https://github.com/prometheus/prometheus/releases/tag/v2.26.0 Примечание переводчика: к моменту публикации перевода последняя версия — 2.28.1.

После деплоймента вы увидите следующие поды:

NAME                                                     READY   STATUS    RESTARTS   AGE alertmanager-prometheus-kube-prometheus-alertmanager-0   2/2     Running   0          69m prometheus-grafana-5c469b9cbf-kn2zk                      2/2     Running   0          69m prometheus-kube-prometheus-operator-68d59d8d59-gvkzk     1/1     Running   0          69m prometheus-kube-state-metrics-685b975bb7-rhstl           1/1     Running   0          69m prometheus-prometheus-kube-prometheus-prometheus-0       2/2     Running   0          69m prometheus-prometheus-node-exporter-mn68b                1/1     Running   0          69m

Для доступа к Prometheus мы пробросим локальный порт на порт сервиса Prometheus.

kubectl port-forward service/prometheus-operated -n observability 9090 Forwarding from 127.0.0.1:9090 -> 9090 Forwarding from [::1]:9090 -> 9090

image
Prometheus на localhost:9090

Как видите, у нас уже есть несколько метрик. Все благодаря поду kube-state-metrics — сервису, который обращается к Kubernetes API и генерирует метрики о состоянии объектов Kubernetes.

Чтобы взаимодействовать с этими метриками и агрегировать их, используйте язык запросов PromQL (Prometheus Query Language). Результаты запроса можно вывести в виде таблицы или графика.

Метрики бывают четырех типов:

  • Счетчик: значение можно только увеличивать или сбросить до нуля.
  • Измеритель: значение можно увеличивать или уменьшать.
  • Гистограмма: несколько временных рядов — совокупные счетчики для бакетов, сумма наблюдаемых значений и общий счетчик событий.
  • Сводка: похожа на гистограмму (показывает сумму наблюдаемых значений и счетчик для событий), но также предоставляет расчет для φ-квантилей.

Гистограмма тоже может давать φ-квантили с помощью функции histogram_quantile, но расчет выполняется на стороне сервера, а не клиента, как в сводке.

Предоставление метрик

Это была теория. Давайте теперь на практике посмотрим, как собирать метрики приложений и сервисов через Prometheus.

Для начала нужно предоставить некоторые метрики. Для этого используем клиент Prometheus для Node.js. У клиента уже есть дефолтные метрики, так что результат мы получим быстро.

Создаем реестр и велим клиенту собирать дефолтные метрики.

const prom = require('prom-client')  const registry = new prom.Registry()  prom.collectDefaultMetrics({     register: registry })  const registerPromMetrics = async (req, res) => {     console.log('Returning Metrics')     try {         res.set('Content-Type', registry.contentType);         res.end(await registry.metrics());     } catch (err) {         res.status(500).end(err);     } }  module.exports = {registerPromMetrics}

Предоставляем эти метрики через endpoint /metrics.

const express = require('express'); const { registerPromMetrics } = require('./telemetry/metrics')  const app = express();  app.use(express.json()); app.get('/metrics',registerPromMetrics) app.listen(process.env.SERVER_PORT, () => {     logger.info(`Server Ready and Listening to port ${process.env.SERVER_PORT} `) })

Вот и все. Метрики готовы.

image
endpoint /metrics на localhost:8080

Чтобы создать кастомные метрики, нужно выбрать тип метрик, а затем сконфигурировать и зарегистрировать его. Для всех типов метрик можно настроить метки, чтобы получить больше контекста и использовать фильтры. На гистограммах можно настроить бакеты, которые объединяют и подсчитывают значения в своем интервале.

Когда вы настроите метрики, вам понадобится метод наблюдения значений. Для этого можно использовать функции промежуточной обработки.

const request_duration = new prom.Histogram({     name: "request_duration_ms",     help: "Request duration histogram",     labelNames: ["method","path","statuscode"],     buckets: [0.1, 5, 10, 15, 50, 100, 200, 500] })  const active_request = new prom.Gauge({     name: "active_requests_count",     help: "Count active requests",     labelNames: ["path"] })  registry.registerMetric(request_duration) registry.registerMetric(active_request)  const getRequestDuration = (req, res, next) => {     const start = Date.now();     res.on('finish', () => {         const duration = Date.now() - start;         request_duration.labels(req.url, req.method, res.statusCode).observe(duration)     });     next(); };  const countActiveRequest = (req, res, next) => {     active_request.inc()     res.on('finish', () => {         active_request.dec()     })     next(); }  module.exports = {getRequestDuration, countActiveRequest, registerPromMetrics}

Затем функции промежуточной обработки загружаются express.

const { countActiveRequest,getRequestDuration,registerPromMetrics } = require('./telemetry/metrics')  const app = express();  app.use(countActiveRequest) app.use(getRequestDuration)      app.use('/',getRouter) app.get('/metrics',registerPromMetrics) app.listen(process.env.SERVER_PORT, () => {     logger.info(`Server Ready and Listening to port ${process.env.SERVER_PORT} `) })

Пример приложения

Все ресурсы, которые мы используем в этой серии статей, доступны в репозитории на GitHub: https://github.com/jonathanbc92/observability-quickstart/tree/master/part1

Пример приложения для этой серии статей будет развернут на Minikube. Оно состоит из трех контейнеров Node.js:

  1. People Service — сервис с простым запросом на получение данных из таблицы в MySQL.
  2. Format Service — сервис, который форматирует сообщение, используя значения из People Service.
  3. Hello Service — сервис, который вызывает предыдущие сервисы и отправляет итоговое сообщение пользователю.

image

У всех микросервисов уже есть дефолтные и кастомные метрики в файле metrics.js.

Чтобы задеплоить весь набор (включая Prometheus), выполните команду make.

Чтобы протестировать приложение, пробросьте порт на порт hello service 8080, а затем сделайте запрос на localhost:8080/sayHello/{name}

curl http://localhost:8081/sayHello/iroh Hey! this is iroh, here is my message to you:  It is important to draw wisdom from many different places

Мониторинг сервисов

Важно понимать, что от отсутствия или наличия оператора при деплойменте Prometheus зависит конфигурация, необходимая для определения target services (целевых сервисов).

Если Prometheus задеплоен без оператора, мы настраиваем targets (цели) в файле конфигурации.

scrape_configs:   - job_name:       'node'     # Override the global default and scrape targets from this job every 5 seconds.     scrape_interval: 5s     static_configs:       - targets: ['localhost:8080', 'localhost:8081']         labels:           group: 'production'       - targets: ['localhost:8082']         labels:           group: 'canary'

Если мы используем оператор, нужно создать кастомные ресурсы — ServiceMonitor. ServiceMonitor указывает, как мониторить сервисы Kubernetes, и автоматически создает конфигурацию скрейпа (примечание переводчика: Конфигурацию автоматического сбора метрик).

image
Схема ServiceMonitor

Кастомный ресурс ServiceMonitor сопоставляет сервисы с метками, указанными в параметре matchLabels в неймспейсе, заданном в namespaceSelector. Сервис может предоставлять много портов, поэтому нужно указать порт и путь, из которого будут собираться метрики.

apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata:   name: all-service-sm   namespace: observability   labels:     release: prometheus   spec:   selector:     matchLabels:       monitor: prometheus   namespaceSelector:     matchNames:     - applications   endpoints:   - port: http     path: /metrics

Проверьте метки, включенные в ServiceMonitor, — Prometheus не будет выбирать ServiceMonitor, у которых нет нужных меток. Что это за метки? В спецификации кастомного ресурса Prometheus видим следующее:

kubectl get prometheuses prometheus-kube-prometheus-prometheus -n observability -o yaml alerting:     alertmanagers:     - apiVersion: v2       name: prometheus-kube-prometheus-alertmanager       namespace: observability       pathPrefix: /       port: web   enableAdminAPI: false   externalUrl: http://prometheus-kube-prometheus-prometheus.observability:9090   image: quay.io/prometheus/prometheus:v2.26.0   listenLocal: false   logFormat: logfmt   logLevel: info   paused: false   podMonitorNamespaceSelector: {}   podMonitorSelector:     matchLabels:       release: prometheus   portName: web   probeNamespaceSelector: {}   probeSelector:     matchLabels:       release: prometheus   replicas: 1   retention: 10d   routePrefix: /   ruleNamespaceSelector: {}   ruleSelector:     matchLabels:       app: kube-prometheus-stack       release: prometheus   securityContext:     fsGroup: 2000     runAsGroup: 2000     runAsNonRoot: true     runAsUser: 1000   serviceAccountName: prometheus-kube-prometheus-prometheus   serviceMonitorNamespaceSelector: {}   serviceMonitorSelector:     matchLabels:       release: prometheus   shards: 1   version: v2.26.0

Параметры serviceMonitorSelector показывают, какие метки должны быть у ServiceMonitor, чтобы Prometheus мог его выбрать.

Теперь нужно просто создать ServiceMonitor:

kubectl apply -f k8s/config/prometheus/servicemonitoring.yml

Если все получилось, перейдем в раздел Targets (Целевые объекты) в меню Status (Статус) в Prometheus. Мы увидим все поды, связанные с отслеживаемыми сервисами.

image
Эндпоинты, с которых Prometheus собирает метрики

Когда новые метрики будут доступны, вы сможете запрашивать их в браузере выражений (expression browser).

image
Размер кучи Node.js в Prometheus

Экспортеры

О сервисах Node.js мы уже поговорили. Как насчет MySQL? Метрики базы данных нам тоже нужны. Чтобы экспортировать имеющиеся метрики из сторонних систем в виде метрик Prometheus, можно использовать экспортеры.

Выбор экспортеров богатый. Вот некоторые из них: https://prometheus.io/docs/instrumenting/exporters/

Мы используем официальный образ экспортера MySQL и запустим его с контейнером MySQL. Для образа требуется переменная среды DATA_SOURCE_NAME, значение которой будет получено из секрета. Поскольку все контейнеры в поде используют одну сеть, можно использовать localhost, чтобы подключиться к MySQL.

kubectl create secret generic mysql-credentials --from-literal=username=root --from-literal=password=admin --from-literal=datasource="exporter:exportpass@(localhost:3306)/tutorial" -n applications

После создания ресурсов в Kubernetes на вкладке Prometheus Targets мы увидим следующее:

image

В браузере выражений Prometheus мы увидим, что метрики MySQL доступны.

image
Метрики MySQL в Prometheus

Теперь можно использовать функцию rate, чтобы посмотреть средний рост для команд select за определенный период. Это показатели только для команд select, выполненных экспортером для сбора метрик.

image

Если сделать то же самое с командами delete, мы увидим 0, потому что команды delete не выполнялись.

image

С помощью Apache Benchmark можно провести нагрузочное тестирование, чтобы создать пик.

image
20к запросов с AB

image
Пик для команд select в Prometheus

Заключение

Как видите, запустить Prometheus с helm-чартом очень просто — вам понадобится пара минут и Minikube. Конечно, в первый раз посмотреть на метрики интересно, но сами по себе они мало что дают. В следующий раз мы поговорим об алертах.


ссылка на оригинал статьи https://habr.com/ru/articles/569860/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *