Grafana Mimir: Backend de Métricas Escalable

Grafana Mimir es una base de datos de métricas de series temporales horizontalmente escalable y compatible con Prometheus, diseñada para almacenar miles de millones de métricas activas con alta disponibilidad y multi-tenancy nativo. A diferencia de Thanos o VictoriaMetrics, Mimir está optimizado específicamente para entornos cloud-native donde los componentes escalan de forma independiente mediante Kubernetes o microservicios. Esta guía cubre la instalación en modo monolítico para empezar y la evolución hacia el modo distribuido.

Requisitos Previos

  • Ubuntu 20.04/22.04 o CentOS 8+/Rocky Linux 8+
  • 4 GB de RAM mínimo en modo monolítico
  • Backend de almacenamiento de objetos: S3, GCS, Azure Blob o MinIO
  • Puerto 8080 disponible
  • Para modo distribuido: Kubernetes o múltiples servidores

Instalación en Modo Monolítico

El modo monolítico ejecuta todos los componentes de Mimir en un único proceso, ideal para empezar o para equipos pequeños:

# Descargar el binario de Mimir
MIMIR_VERSION=2.11.0
wget "https://github.com/grafana/mimir/releases/download/mimir-${MIMIR_VERSION}/mimir-linux-amd64" -P /tmp

sudo mv /tmp/mimir-linux-amd64 /usr/local/bin/mimir
sudo chmod +x /usr/local/bin/mimir

# Verificar la instalación
mimir --version

# Crear usuario y directorios
sudo useradd -r -s /bin/false mimir
sudo mkdir -p /etc/mimir /var/lib/mimir
sudo chown -R mimir:mimir /var/lib/mimir

Configuración del Backend de Almacenamiento

Crea el archivo de configuración principal en /etc/mimir/mimir.yaml:

# /etc/mimir/mimir.yaml
# Configuración para modo monolítico con MinIO como almacenamiento

# Objetivo: ejecutar todos los componentes en un proceso
target: all,alertmanager

# Configuración del servidor HTTP y gRPC
server:
  http_listen_port: 8080
  grpc_listen_port: 9095
  log_level: info

# Configuración del anillo (para componentes distribuidos dentro del monolítico)
ingester:
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: memberlist
    replication_factor: 1

distributor:
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: memberlist

# Descubrimiento de peers via gossip (memberlist)
memberlist:
  join_members:
    - 127.0.0.1

# Configuración del almacenamiento de bloques TSDB
blocks_storage:
  backend: s3
  s3:
    bucket_name: mimir-blocks
    endpoint: minio:9000
    access_key_id: minio_access_key
    secret_access_key: minio_secret_key
    insecure: true  # Deshabilitar si MinIO usa TLS
  tsdb:
    dir: /var/lib/mimir/tsdb
    block_ranges_period: [2h]
    retention_period: 48h  # Retención local antes de subir a S3
  bucket_store:
    sync_dir: /var/lib/mimir/tsdb-sync

# Configuración del ruler (para alerting)
ruler:
  rule_path: /var/lib/mimir/rules
  alertmanager_url: http://localhost:8080/alertmanager

# Configuración de alertmanager embebido
alertmanager:
  data_dir: /var/lib/mimir/alertmanager
  sharding_ring:
    replication_factor: 1

# Límites globales por tenant
limits:
  # Máximo de métricas activas por tenant
  max_global_series_per_user: 1500000
  # Retención de datos
  compactor_blocks_retention_period: 365d
  # Máximo de muestras por consulta
  max_fetched_samples_per_query: 50000000

# Configuración del compactador
compactor:
  data_dir: /var/lib/mimir/compactor
  sharding_ring:
    kvstore:
      store: memberlist

# Configuración del almacenamiento para reglas y alertas
ruler_storage:
  backend: s3
  s3:
    bucket_name: mimir-ruler
    endpoint: minio:9000
    access_key_id: minio_access_key
    secret_access_key: minio_secret_key
    insecure: true

alertmanager_storage:
  backend: s3
  s3:
    bucket_name: mimir-alertmanager
    endpoint: minio:9000
    access_key_id: minio_access_key
    secret_access_key: minio_secret_key
    insecure: true
# Proteger el archivo de configuración
sudo chmod 640 /etc/mimir/mimir.yaml
sudo chown mimir:mimir /etc/mimir/mimir.yaml

# Crear los buckets en MinIO
mc alias set local http://minio:9000 minio_access_key minio_secret_key
mc mb local/mimir-blocks
mc mb local/mimir-ruler
mc mb local/mimir-alertmanager

# Crear el servicio systemd
sudo tee /etc/systemd/system/mimir.service > /dev/null <<EOF
[Unit]
Description=Grafana Mimir
After=network.target

[Service]
Type=simple
User=mimir
Group=mimir
ExecStart=/usr/local/bin/mimir \
    -config.file=/etc/mimir/mimir.yaml \
    -usage-stats.enabled=false
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
LimitNPROC=4096

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable mimir --now

# Verificar que Mimir está corriendo
sudo systemctl status mimir
curl http://localhost:8080/ready
curl http://localhost:8080/api/v1/status/config

Configurar Prometheus para Remote Write

# /etc/prometheus/prometheus.yml

global:
  scrape_interval: 15s
  external_labels:
    cluster: produccion
    replica: prometheus-1

remote_write:
  - url: http://mimir:8080/api/v1/push
    # Para multi-tenancy, especificar el tenant ID en la cabecera
    headers:
      X-Scope-OrgID: "mi-organizacion"
    queue_config:
      capacity: 10000
      max_shards: 200
      max_samples_per_send: 500
      batch_send_deadline: 5s
      min_backoff: 30ms
      max_backoff: 5s
# Reiniciar Prometheus
sudo systemctl restart prometheus

# Verificar que los datos llegan a Mimir
curl "http://localhost:8080/prometheus/api/v1/query?query=up" \
  -H "X-Scope-OrgID: mi-organizacion" | python3 -m json.tool

Multi-tenancy

Mimir soporta multi-tenancy de forma nativa mediante el header X-Scope-OrgID:

# Enviar datos como tenant "equipo-backend"
curl -X POST http://mimir:8080/api/v1/push \
  -H "X-Scope-OrgID: equipo-backend" \
  -H "Content-Type: application/x-protobuf" \
  --data-binary @metricas.pb

# Consultar datos del tenant "equipo-backend"
curl "http://mimir:8080/prometheus/api/v1/query?query=up" \
  -H "X-Scope-OrgID: equipo-backend"

# Consultar datos de múltiples tenants a la vez
curl "http://mimir:8080/prometheus/api/v1/query?query=up" \
  -H "X-Scope-OrgID: equipo-backend|equipo-frontend|infraestructura"

Configurar límites personalizados por tenant:

# En mimir.yaml, sección overrides
overrides:
  equipo-backend:
    max_global_series_per_user: 5000000
    compactor_blocks_retention_period: 730d  # 2 años
  equipo-frontend:
    max_global_series_per_user: 500000
    compactor_blocks_retention_period: 90d

Modo Distribuido

Para alta disponibilidad y mayor escala, Mimir separa sus componentes. Ejemplo con Docker Compose:

# docker-compose-mimir-distribuido.yml (estructura básica)
version: "3.8"

services:
  # Ingestores (almacenamiento en memoria de datos recientes)
  ingester-1:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=ingester", "-ingester.ring.instance-id=ingester-1"]
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro
      - ingester-1-data:/var/lib/mimir

  ingester-2:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=ingester", "-ingester.ring.instance-id=ingester-2"]
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro
      - ingester-2-data:/var/lib/mimir

  # Distribuidores (reciben el remote write y distribuyen entre ingestores)
  distributor:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=distributor"]
    ports:
      - "8080:8080"
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro

  # Queriers (ejecutan consultas PromQL)
  querier:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=querier"]
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro

  # Store Gateway (sirve bloques del object storage)
  store-gateway:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=store-gateway"]
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro

  # Compactador
  compactor:
    image: grafana/mimir:latest
    command: ["-config.file=/etc/mimir/mimir.yaml", "-target=compactor"]
    volumes:
      - ./mimir.yaml:/etc/mimir/mimir.yaml:ro

Integración con Grafana

# Añadir Mimir como datasource en Grafana
curl -X POST http://grafana:3000/api/datasources \
  -u admin:contraseña_grafana \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Mimir",
    "type": "prometheus",
    "url": "http://mimir:8080/prometheus",
    "access": "proxy",
    "isDefault": true,
    "jsonData": {
      "timeInterval": "15s",
      "httpMethod": "POST",
      "customQueryParameters": "X-Scope-OrgID=mi-organizacion"
    },
    "httpHeaders": {
      "X-Scope-OrgID": "mi-organizacion"
    }
  }'

Importa los dashboards oficiales de Mimir desde Grafana.com para monitorear el propio Mimir (IDs: 17564, 17565, etc.).

Solución de Problemas

Mimir no arranca:

# Revisar logs
sudo journalctl -u mimir -n 100 --no-pager

# Verificar acceso al bucket de almacenamiento
curl http://minio:9000/mimir-blocks -v

# El error más común es configuración incorrecta del bucket S3/MinIO
# Verificar las credenciales y el nombre del bucket

Error "context deadline exceeded" en remote write:

# Mimir puede estar sobrecargado o no disponible
# Verificar el estado de Mimir
curl http://mimir:8080/ready
curl http://mimir:8080/metrics | grep mimir_ingester

# Aumentar el timeout en Prometheus
remote_write:
  - url: http://mimir:8080/api/v1/push
    remote_timeout: 60s

Consultas lentas:

# Activar el Query Frontend como caché de consultas
# El Query Frontend divide las consultas largas en subconsultas más cortas
# y las cachea en Memcached o Redis

# Añadir al mimir.yaml:
query_frontend:
  cache_results: true
  results_cache:
    backend: memcached
    memcached:
      addresses: dns+memcached:11211

Alto consumo de memoria en los ingestores:

# Los ingestores mantienen datos en memoria durante 2 horas antes de subirlos
# Limitar el número de series activas por ingester
limits:
  max_global_series_per_user: 1000000
  # Distribuir entre los ingestores (si hay 3 ingestores):
  max_global_series_per_metric: 50000

Conclusión

Grafana Mimir es la solución más completa para entornos que requieren métricas a escala empresarial con multi-tenancy, alta disponibilidad y retención a largo plazo mediante almacenamiento en la nube. Su arquitectura de microservicios permite escalar cada componente de forma independiente según los cuellos de botella: más ingestores para mayor tasa de escritura, más queriers para mayor carga de consultas. El modo monolítico facilita enormemente el inicio y la evaluación antes de comprometerse con el despliegue distribuido completo.