Monitoring Microservices with Prometheus and Grafana

Navendu Pottekkat

Navendu Pottekkat

June 8, 2023

Ecosystem

El monitoreo continuo es fundamental para hacer que los sistemas de microservicios sean robustos. Sin un monitoreo adecuado, los microservicios pueden saturarse rápidamente, lo que lleva a errores y pérdida de rendimiento.

A través del monitoreo continuo, los desarrolladores pueden detectar problemas en sus servicios tan pronto como surjan y tomar medidas para evitar daños significativos. También proporciona información sobre cómo están funcionando sus servicios, lo que permite tomar decisiones informadas.

Este artículo presentará cómo puedes configurar el monitoreo en tu aplicación de microservicios utilizando dos de las herramientas más populares en este ámbito: Prometheus y Grafana.

El código fuente y el archivo Docker Compose para este tutorial están disponibles en pottekkat/monitoring-101.

Conceptos básicos de Prometheus

Prometheus es una herramienta de monitoreo y alertas de código abierto. "Extrae" métricas (mediciones) de los microservicios enviando solicitudes HTTP y almacena los resultados en una base de datos de series temporales.

Puedes instrumentar tus servicios utilizando las bibliotecas de cliente proporcionadas por Prometheus. Esto te permitirá crear y recopilar métricas personalizadas de tus servicios.

Prometheus también tiene exportadores que te permiten extraer métricas que no están en formato Prometheus. Un exportador actúa como intermediario y transforma los datos exportados en un formato legible para Prometheus.

1-prometheus-architecture.png

Prometheus proporciona un potente lenguaje de consulta, PromQL, para trabajar con estos datos recopilados. Puedes usar PromQL para crear consultas complejas que filtren, agreguen y transformen los datos al formato deseado.

Además de extraer métricas, Prometheus también puede activar alertas cuando se superan los umbrales establecidos. El mecanismo de alertas es altamente configurable y puede enviar notificaciones a lugares como Slack o correo electrónico.

Prometheus tiene una interfaz gráfica que te permite visualizar fácilmente las métricas recopiladas. También se integra con otras herramientas avanzadas de visualización como Grafana.

prometheus-dashboard.png

Tipos de métricas

Prometheus ofrece cuatro tipos principales de métricas:

  1. Contador: representa un contador único que aumenta monótonamente. Su valor puede aumentar o reiniciarse a cero al reiniciar. Puedes usarlo para representar métricas como el número de solicitudes atendidas.
  2. Gauge: representa un valor numérico que puede subir o bajar. Puedes usarlo para representar valores como el uso de memoria o el número de solicitudes por segundo.
  3. Histograma: muestrea datos en cubos configurables. Úsalo para representar valores como la duración de las solicitudes o el tamaño de las respuestas.
  4. Resumen: similar al histograma, también calcula valores configurables en una ventana de tiempo deslizante.

Puedes aprender más sobre estos tipos de métricas y cómo usarlos en la documentación oficial.

Aplicación de ejemplo

Nuestra aplicación de ejemplo consistirá en una puerta de enlace API, una aplicación en Go y una aplicación en Python.

2-sample-app-flowchart.png

La aplicación devolverá "¡Hola <nombre>!" en el idioma que elijas con el <nombre> que proporciones. Apache APISIX será la puerta de enlace API que dirige el tráfico a tus servicios.

El siguiente diagrama muestra cómo funciona el sistema.

3-sample-app-sequence.png

  1. El usuario envía una solicitud GET a APISIX, el punto de entrada de la aplicación.
  2. APISIX reenvía la solicitud al servicio Go.
  3. El servicio Go envía una solicitud GET al servicio Python para obtener "Hola" en el idioma especificado.
  4. El servicio Python responde con la traducción requerida de "Hola".
  5. El servicio Go crea la respuesta requerida utilizando el nombre proporcionado en la consulta y la envía a APISIX.
  6. APISIX reenvía la respuesta al usuario.

Configurando Prometheus para recopilar métricas

Instrumentaremos y exportaremos métricas de todos los servicios en nuestra aplicación y las recopilaremos en Prometheus. Comenzaremos con nuestra puerta de enlace API, Apache APISIX.

Exportando métricas desde APISIX

Apache APISIX es una puerta de enlace API nativa de la nube y de código abierto.

No necesitas conocer APISIX para seguir este tutorial, y puedes usar el archivo Docker Compose proporcionado para configurar todo. Para aprender más sobre APISIX, visita api7.ai/apisix.

APISIX ofrece un Plugin de Prometheus que exporta fácilmente métricas en formato Prometheus. Puedes configurar el Plugin en tu archivo de configuración de APISIX:

apisix:
  enable_admin: false # ejecuta APISIX en modo independiente
  config_center: yaml # usa un archivo YAML para la configuración en lugar de almacenarla en etcd
plugin_attr:
  prometheus:
    export_uri: /prometheus/metrics # habilita el Plugin de Prometheus y exporta las métricas a esta URI
    enable_export_server: false # exporta las métricas en el puerto predeterminado del plano de datos

Ahora podemos habilitar el Plugin en cada Ruta convirtiéndolo en una Regla global:

routes:
  # dirige las solicitudes a /hello/* al go-app
  - uri: /hello/*
    upstream:
      type: roundrobin
      nodes:
        "go-app:8080": 1
    plugins:
      # elimina el prefijo "/hello" antes de reenviar la solicitud al go-app
      proxy-rewrite:
        regex_uri:
          - "/hello/(.*)"
          - "/$1"
  # exporta las métricas de Prometheus a la URI especificada
  - uri: /prometheus/metrics
    plugins:
      public-api:
# habilita el Plugin de Prometheus globalmente en todas las Rutas
global_rules:
  - id: 1
    plugins:
      prometheus:
        prefer_name: true
#END

Esto exportará las métricas al punto final /prometheus/metrics en Apache APISIX.

Puedes aprender más sobre las métricas disponibles en la documentación.

Instrumentando y exportando métricas desde el servicio Go

Prometheus tiene una biblioteca oficial de cliente para Go para instrumentar aplicaciones en Go.

Por defecto, Prometheus expondrá las métricas predeterminadas de Go. También puedes crear tus propias métricas específicas de la aplicación.

En nuestro servicio, expondremos las métricas predeterminadas y crearemos nuestra propia métrica de contador para rastrear el número de solicitudes:

package main

import (
  "encoding/json"
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
  "os"

  // Paquetes de Prometheus
  "github.com/prometheus/client_golang/prometheus"
  "github.com/prometheus/client_golang/prometheus/promauto"
  "github.com/prometheus/client_golang/prometheus/promhttp"
)

// Response almacena el Mensaje obtenido del python-app
type Response struct {
  Message string `json:"message"`
}

// idioma y nombre predeterminados
var (
  lang = "en"
  name = "John"
)

// crea una nueva métrica de contador personalizada de Prometheus
var pingCounter = promauto.NewCounter(
  prometheus.CounterOpts{
    Name: "go_app_request_count",
    Help: "Número de solicitudes manejadas por el go-app",
  },
)

// HelloHandler maneja las solicitudes al go-app
func HelloHandler(w http.ResponseWriter, r *http.Request) {
  lang = r.URL.String()
  name = r.URL.Query()["name"][0]
  
  fmt.Println("Solicitud para", lang, "con nombre", name)
  pingCounter.Inc()
  
  pUrl := os.Getenv("PYTHON_APP_URL")
  if len(pUrl) == 0 {
    pUrl = "localhost"
  }

  // llama al python-app para obtener la traducción
  resp, err := http.Get("http://" + pUrl + ":8000" + lang)
  if err != nil {
    log.Fatalln(err)
  }

  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatalln(err)
  }

  resp.Body.Close()

  var m Response
  json.Unmarshal(body, &m)

  // envía la respuesta con "¡Hola nombre!" en el idioma especificado
  fmt.Fprintf(w, "%s %s!", m.Message, name)
}

func main() {
  // expone las métricas de Prometheus
  http.Handle("/metrics", promhttp.Handler())
  http.HandleFunc("/", HelloHandler)
  
  http.ListenAndServe(":8080", nil)
}

Esto expondrá las métricas al punto final /metrics. Puedes aprender más sobre la biblioteca de cliente para Go en su repositorio de GitHub.

Instrumentando y exportando métricas desde el servicio Python

Prometheus también tiene una biblioteca oficial de cliente para Python. También hay bibliotecas de terceros adaptadas a casos de uso específicos.

Nuestro servicio usa FastAPI, y utilizaremos la biblioteca prometheus_fastapi_instrumentator para instrumentarlo:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()

hello = {"en": "Hello", "fr": "Bonjour", "es": "Hola", "ml": "ഹലോ"}

# expone las métricas predeterminadas de Python al punto final /metrics
Instrumentator().instrument(app).expose(app)

@app.get("/{lang}")
async def get_hello(lang):
    return {"message": hello[lang]}

Puedes aprender más sobre cómo crear métricas personalizadas en la documentación.

Configurando Prometheus

Ahora podemos recopilar estas métricas en Prometheus.

Puedes configurar Prometheus para recopilar métricas de cada uno de los servicios. Por defecto, Prometheus busca métricas en la ruta /metrics:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  
  - job_name: "go-app"
    static_configs:
      - targets: ["go-app:8080"]

  - job_name: "python-app"
    static_configs:
      - targets: ["python-app:8000"]

  - job_name: "apisix"
    static_configs:
      - targets: ["apisix:9080"]
    metrics_path: "/prometheus/metrics"

¡Eso es todo! Ahora, si abres el panel de control de Prometheus (predeterminado en el puerto 9090) y haces clic en "Status" en la barra de navegación y luego en "Targets", podrás ver el estado de las métricas que se están recopilando de tus servicios.

prometheus-target-status.png

Consultando y visualizando métricas en Prometheus

Ahora puedes usar el panel de control de Prometheus para ejecutar consultas y expresiones complejas.

prometheus-query.png

Puedes aprender más sobre cómo consultar Prometheus en la documentación oficial.

Usando Grafana para consultar Prometheus

Grafana es una plataforma de visualización de datos de código abierto que funciona con Prometheus para proporcionar una herramienta completa para recopilar, consultar y visualizar métricas.

Prometheus es bueno para recopilar métricas y consultar, pero carece de herramientas para crear visualizaciones significativas. Grafana supera esta limitación transformando las métricas recopiladas en visualizaciones.

Grafana también es compatible con muchas otras fuentes de datos además de Prometheus.

Una vez que hayas desplegado Grafana, puedes abrir la interfaz web (predeterminada en el puerto 3000).

Primero, debes agregar Prometheus como una fuente de datos. Para hacer esto, ve a /datasources o "Configuration" y "Data sources". Haz clic en "Add data source" y selecciona Prometheus. Especifica dónde está desplegado Prometheus, guarda y prueba la conexión.

grafana-add-prometheus.png

Usando paneles preconstruidos de Grafana

Grafana aloja un repositorio público de paneles que contiene paneles preconstruidos de Grafana. Puedes usarlos en tu instancia de Grafana para visualizar rápidamente métricas relevantes.

Usaremos el panel Go Processes que procesará y visualizará el estado del proceso publicado por la biblioteca de cliente de Prometheus para Go.

Para importar esta plantilla, primero copia su ID (6671) del repositorio de paneles. En tu interfaz de Grafana, ve a "Dashboards" y selecciona "Import". Pega el ID que copiaste y haz clic en "Load".

grafana-dashboard.png

También puedes explorar otros paneles preconstruidos o crear los tuyos propios. Consulta la documentación para aprender más sobre esto.

¿Qué sigue?

¡Eso es todo por este tutorial!

Este artículo fue solo una introducción sobre cómo puedes configurar el monitoreo en tus servicios, y te animo a aprender más sobre Prometheus y Grafana en los recursos mencionados a continuación:

El código completo y el archivo Docker Compose para este tutorial están disponibles en pottekkat/monitoring-101.

Tags: