...

среда, 28 июля 2021 г.

[Перевод] Секреты 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. Конечно, в первый раз посмотреть на метрики интересно, но сами по себе они мало что дают. В следующий раз мы поговорим об алертах.

Adblock test (Why?)

Комментариев нет:

Отправить комментарий