Las 3 mejores opciones para implementar Loki escalable en Kubernetes

Las 3 mejores opciones para implementar Loki escalable en Kubernetes

Modelos de Despliegue para una Arquitectura Escalable de Agregación de Logs usando Loki

Desplegar un Loki escalable no es una tarea sencilla. Ya hemos hablado sobre Loki en publicaciones anteriores en el sitio, y se está volviendo cada vez más popular, y su uso se vuelve mucho más regular cada día. Es por eso que creo que tiene sentido incluir otra publicación sobre la Arquitectura de Loki.

Loki tiene varias ventajas que lo promueven como una opción predeterminada para desplegar una Pila de Agregación de Logs. Una de ellas es su escalabilidad porque puedes ver a través de diferentes modelos de despliegue cuántos componentes te gustaría desplegar y sus responsabilidades. Así que el objetivo del tema es mostrarte cómo desplegar una solución escalable de Loki y esto se basa en dos conceptos: componentes disponibles y cómo los agrupas.

Así que comenzaremos con los diferentes componentes:

  • ingester: responsable de escribir datos de logs en backends de almacenamiento a largo plazo (DynamoDB, S3, Cassandra, etc.) en la ruta de escritura y devolver datos de logs para consultas en memoria en la ruta de lectura.
  • distributor: responsable de manejar flujos entrantes por parte de los clientes. Es el primer paso en la ruta de escritura para los datos de logs.
  • query-frontend: servicio opcional que proporciona los puntos finales de la API del querier y puede usarse para acelerar la ruta de lectura.
  • querier: servicio que maneja consultas usando el lenguaje de consulta LogQL, obteniendo logs de los ingesters y del almacenamiento a largo plazo.
  • ruler: responsable de evaluar continuamente un conjunto de consultas configurables y realizar una acción basada en el resultado.

Luego puedes unirlos en diferentes grupos, y dependiendo del tamaño de estos grupos, tienes una topología de despliegue diferente, como se muestra a continuación:

Las 3 mejores opciones para implementar Loki escalable en Kubernetes
Modo de Despliegue Monolítico de Loki
  • Monolito: Como puedes imaginar, todos los componentes se ejecutan juntos en una sola instancia. Esta es la opción más simple y se recomienda como un punto de partida de 100 GB / día. Incluso puedes escalar este despliegue, pero escalará todos los componentes simultáneamente, y debería tener un estado de objeto compartido.
Las 3 mejores opciones para implementar Loki escalable en Kubernetes
Modo de Despliegue Escalable Simple de Loki
  • Modelo de Despliegue Escalable Simple: Este es el segundo nivel, y puede escalar hasta varios TB de logs por día. Consiste en dividir los componentes en dos perfiles diferentes: lectura y escritura.
Las 3 mejores opciones para implementar Loki escalable en Kubernetes
Modo de Despliegue de Microservicios de Loki
  • Microservicios: Eso significa que cada componente será gestionado de manera independiente, dándote todo el poder en tus manos para escalar cada uno de estos componentes por separado.

Definir el modelo de despliegue de cada instancia es muy fácil, y se basa en un solo parámetro llamado target. Así que dependiendo del valor del target seguirá uno de los modelos de despliegue anteriores:

  • all (por defecto): Se desplegará en modo monolítico.
  • write: Será la ruta de escritura en el modelo de despliegue escalable simple
  • read: Será el grupo de lectura en el modelo de despliegue escalable simple
  • ingester, distributor, query-frontend, query-scheduler, querier, index-gateway, ruler, compactor: Valores individuales para desplegar un solo componente para el modelo de despliegue de microservicios.

El argumento target ayudará para un tipo de despliegue on-premises. Aún así, si estás usando Helm para la instalación, Loki ya proporciona diferentes charts de helm para los otros modelos de despliegue:

Pero todos esos charts de helm se basan en el mismo principio comentado anteriormente sobre definir el rol de cada instancia usando el argumento target, como puedes ver en la imagen a continuación:

Las 3 mejores opciones para implementar Loki escalable en Kubernetes

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

ServiceMonitor y PodMonitor de Prometheus: ¡No te pierdas los nuevos conceptos!

black flat screen tv turned on near black and gray audio component

Descubre las diferencias entre dos de los CRDs más utilizados del Operador Prometheus y cómo usar cada uno de ellos.

Conceptos de Prometheus: ServiceMonitor y PodMonitor

Foto de Ibrahim Boran en Unsplash

ServiceMonitor y PodMonitor son términos que comenzarás a ver más a menudo cuando se hable de usar Prometheus. Hemos cubierto mucho sobre Prometheus en artículos anteriores. Es una de las principales referencias cuando hablamos de monitoreo en un entorno nativo de la nube y está especialmente enfocado en el ecosistema de Kubernetes.

Prometheus tiene un nuevo modelo de implementación bajo el Marco del Operador de Kubernetes en tiempos recientes. Eso ha generado varios cambios en términos de recursos y cómo configuramos varios aspectos del monitoreo de nuestras cargas de trabajo. Algunos de estos conceptos ahora se gestionan como Definición de Recurso Personalizado (CRD) que se incluyen para simplificar la configuración del sistema y estar más alineados con las capacidades de la propia plataforma de Kubernetes. Esto es genial pero, al mismo tiempo, cambia cómo necesitamos usar esta excelente herramienta de monitoreo para cargas de trabajo nativas de la nube.

Hoy, cubriremos dos de estos nuevos CRDs, uno de los más relevantes: ServiceMonitor y PodMonitor. Estos son los nuevos objetos que especifican los recursos que estarán bajo el alcance de monitoreo para la plataforma, y cada uno de ellos cubre un tipo diferente de objeto, como puedes imaginar: Servicios y Pods.

Cada uno de ellos tiene su archivo de definición con sus campos y metadatos particulares, y para destacarlos, presentaré un ejemplo para cada uno de ellos a continuación:

Service Monitor

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    serviceMonitorSelector: prometheus
  name: prometheus
  namespace: prometheus
spec:
  endpoints:
  - interval: 30s
    targetPort: 9090
    path: /metrics
  namespaceSelector:
    matchNames:
    - prometheus
  selector:
    matchLabels:
      operated-prometheus: "true"

Pod Monitor

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: front-end
  labels:
    name: front-end
spec:
  namespaceSelector:
    matchNames:
      - sock-shop
  selector:
    matchLabels:
      name: front-end
  podMetricsEndpoints:
  - targetPort: 8079

Como puedes ver, las definiciones de los componentes son muy similares y muy intuitivas, enfocándose en el selector para detectar qué pods o servicios debemos monitorear y algunos datos sobre el objetivo específico del monitoreo, para que Prometheus sepa cómo extraerlos.

Si deseas echar un vistazo más en detalle a cualquier opción que puedas configurar en este CRD, te recomendaría que eches un vistazo a esta URL que incluye una documentación detallada campo por campo de los CRDs más comunes:

Estos componentes pertenecerán a la definición de tus cargas de trabajo, lo que significa que la creación y el mantenimiento de estos objetos serán responsabilidad de los desarrolladores de la aplicación.

Eso es genial por varias razones:

  • Incluirá el aspecto de Monitoreo del propio componente, por lo que nunca olvidarás agregar la configuración de un componente específico. Eso significa que se puede incluir en los archivos YAML duplicados o en el Helm Chart o en recursos de Kustomize como otro recurso necesario.
  • Descentralizará la configuración de monitoreo haciéndola más ágil, y progresará a medida que lo hagan los componentes de software.
  • Reducirá el impacto en otros componentes monitoreados ya que no hay necesidad de actuar en ningún archivo o recurso estándar, por lo que cualquier carga de trabajo diferente continuará funcionando como se espera.

Ambos objetos son muy similares en sus propósitos ya que ambos extraen todos los endpoints que coinciden con el selector que agregamos. Entonces, ¿en qué casos debería usar uno u otro?

La respuesta será sencilla. Por defecto, optarás por un ServiceMonitor porque proporcionará las métricas del propio servicio y de cada uno de los endpoints que tiene el servicio, por lo que cada uno de los pods que están implementando el servicio será descubierto y extraído como parte de esta acción.

Entonces, ¿en qué casos debería usar PodMonitor? Donde la carga de trabajo que estás tratando de monitorear no actúa detrás de un servicio, por lo que al no haber un servicio definido, no puedes usar ServiceMonitor. ¿Quieres algunos ejemplos de eso? ¡Traigamos algunos!

  • Servicios que interactúan usando otros protocolos que no son basados en HTTP, como Kafka, SQS/SNS, JMS, o similares.
  • Componentes como CronJobs, DaemonSets, o que no exponen ningún modelo de conexión entrante.

Así que espero que este artículo te ayude a entender la principal diferencia entre esos objetos y profundizar un poco más en cómo funcionan los nuevos recursos del Marco del Operador Prometheus. Continuaremos cubriendo otros aspectos en próximos artículos.

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Promtail: Conecta Registros y Métricas en Tu Monitorización

Promtail: Conecta Registros y Métricas en Tu Monitorización

Promtail es la solución cuando necesitas proporcionar métricas que solo están presentes en los rastros de registro del software que necesitas monitorear para proporcionar una plataforma de monitoreo consistente

Es un entendimiento común que tres pilares en el mundo de la observabilidad nos ayudan a obtener una vista completa del estado de nuestras propias plataformas y sistemas: Registros, Trazas y Métricas.

Para proporcionar un resumen de las diferencias entre cada uno de ellos:

  • Las métricas son los contadores sobre el estado de los diferentes componentes desde una vista técnica y de negocio. Así que aquí podemos ver cosas como el consumo de CPU, el número de solicitudes, el uso de memoria o disco…
  • Los registros son los diferentes mensajes que cada una de las piezas de software en nuestra plataforma proporciona para entender su comportamiento actual y detectar algunas situaciones no esperadas.
  • La traza es la diferente información sobre el flujo de solicitudes de extremo a extremo a través de la plataforma con los servicios y sistemas que han sido parte de ese flujo y datos relacionados con esa solicitud concreta.

Tenemos soluciones que afirman abordar todos ellos, principalmente en el software empresarial con Dynatrace, AppDynamics y similares. Y por otro lado, intentamos ir con una solución específica para cada uno de ellos que podamos integrar fácilmente juntos y hemos discutido mucho sobre esas opciones en artículos anteriores.

Pero, algunas situaciones en ese software no funcionan siguiendo este camino porque vivimos en la era más heterogénea. Todos abrazamos, en algún nivel, el enfoque políglota en las nuevas plataformas. En algunos casos, podemos ver que el software está utilizando rastros de registro para proporcionar datos relacionados con métricas u otros asuntos, y aquí es cuando necesitamos confiar en piezas de software que nos ayuden a «arreglar» esa situación, y Promtail hace específicamente eso.

Promtail es principalmente un reenviador de registros similar a otros como fluentd o fluent-bit de CNCF o logstash del stack ELK. En este caso, esta es la solución de Grafana Labs, y como puedes imaginar, esto es parte del stack de Grafana con Loki para ser el «cerebro» que cubrimos en este artículo que te recomiendo que eches un vistazo si aún no lo has leído:

Promtail tiene dos formas principales de comportarse como parte de esta arquitectura, y la primera es muy similar a otras en este espacio, como comentamos antes. Nos ayuda a enviar nuestros rastros de registro desde nuestros contenedores a la ubicación central que principalmente será Loki y puede ser una diferente y proporcionar las opciones habituales para jugar y transformar esos rastros como podemos hacer en otras soluciones. Puedes ver todas las opciones en el enlace a continuación, pero como puedes imaginar, esto incluye transformación, filtrado, análisis, y así sucesivamente.

Pero lo que hace a promtail tan diferente es solo una de las acciones que puedes hacer, y esa acción es metrics. Metrics proporciona una forma específica de, basado en los datos que estamos leyendo de los registros, crear métricas de Prometheus que un servidor de Prometheus puede recolectar. Eso significa que puedes usar los rastros de registro que estás procesando que pueden ser algo como esto:

[2021–06–06 22:02.12] Nueva solicitud recibida para customer_id: 123

[2021–06–06 22:02.12] Nueva solicitud recibida para customer_id: 191

[2021–06–06 22:02.12] Nueva solicitud recibida para customer_id: 52

Con esta información aparte de enviar esas métricas a la ubicación central para crear una llamada de métrica, por ejemplo: `total_request_count` que será generada por el agente promtail y también expuesta por él y siendo capaz también de usar un enfoque de métricas incluso para sistemas o componentes que no proporcionan una forma estándar de hacer eso como una API de métricas formal.

Y la forma de hacer esto está muy bien integrada con la configuración. Esto se hace con una etapa adicional (así es como llamamos a las acciones que podemos hacer en Promtail) que se llama metrics.

El esquema de esa etapa de métrica es sencillo, y si estás familiarizado con Prometheus, verás lo directo que es desde una definición de métricas de Prometheus a este fragmento:

# Un mapa donde la clave es el nombre de la métrica y el valor es un tipo de
# métrica específico.
metrics:
  [<string>: [ <metric_counter> | <metric_gauge> | <metric_histogram> ] ...]

Así que comenzamos definiendo el tipo de métricas que nos gustaría definir, y tenemos las habituales: contador, gauge o histograma, y para cada uno de ellos, tenemos un conjunto de opciones para poder declarar nuestras métricas como puedes ver aquí para una Métrica de Contador

# El tipo de métrica. Debe ser Counter.
type: Counter

# Describe la métrica.

[description: <string>]

# Define un nombre de prefijo personalizado para la métrica. Si no está definido, el nombre predeterminado «promtail_custom_» será prefijado.

[prefix: <string>]

# Clave del mapa de datos extraídos para usar en la métrica, # por defecto al nombre de la métrica si no está presente.

[source: <string>]

# Los valores de las etiquetas en las métricas son dinámicos, lo que puede causar que las métricas exportadas se vuelvan obsoletas (por ejemplo, cuando un flujo deja de recibir registros). # Para prevenir el crecimiento ilimitado del endpoint /metrics, cualquier métrica que no haya sido actualizada dentro de este tiempo será eliminada. # Debe ser mayor o igual a ‘1s’, si no está definido el valor predeterminado es ‘5m’

[max_idle_duration: <string>]

config: # Si está presente y es verdadero, todas las líneas de registro serán contadas sin # intentar coincidir la fuente con el mapa extraído. # Es un error especificar `match_all: true` y también especificar un `value`

[match_all: <bool>]

# Si está presente y es verdadero, todos los bytes de la línea de registro serán contados. # Es un error especificar `count_entry_bytes: true` sin especificar `match_all: true` # Es un error especificar `count_entry_bytes: true` sin especificar `action: add`

[count_entry_bytes: <bool>]

# Filtra los datos de origen y solo cambia la métrica # si el valor objetivo coincide exactamente con la cadena proporcionada. # Si no está presente, todos los datos coincidirán.

[value: <string>]

# Debe ser «inc» o «add» (insensible a mayúsculas). Si # se elige inc, el valor de la métrica aumentará en 1 por cada # línea de registro recibida que pase el filtro. Si se elige add, # el valor extraído debe ser convertible a un flotante positivo # y su valor se sumará a la métrica. action: <string>

Y con eso, tendrás tu métrica creada y expuesta, solo esperando que un servidor de Prometheus la recolecte. Si te gustaría ver todas las opciones disponibles, toda esta documentación está disponible en la documentación de Grafana Labs que puedes consultar en el enlace:

Espero que encuentres esto interesante y una forma útil de mantener toda tu información de observabilidad gestionada correctamente usando la solución adecuada y proporcionar una solución para estas piezas de software que no siguen tu paradigma.

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Verificación de Salud de Kubernetes: Cómo Hacerlo Más Simple

Verificación de Salud de Kubernetes: Cómo Hacerlo Más Simple

KubeEye te apoya en la tarea de asegurar que tu clúster esté funcionando bien y asegurar que se sigan todas tus mejores prácticas.

Kubernetes se ha convertido en la nueva norma para desplegar nuestras aplicaciones y otras opciones sin servidor, por lo que la administración de estos clústeres se ha vuelto crítica para la mayoría de las empresas, y realizar una Verificación de Salud de Kubernetes adecuada se está volviendo crítico.

Esta tarea está clara que no es una tarea fácil. Como siempre, la flexibilidad y el poder que la tecnología proporciona a los usuarios (en este caso, los desarrolladores) también viene con una compensación con la complejidad de la operación y gestión. Y esto no es una excepción a eso.

Hemos evolucionado, incluyendo opciones gestionadas que simplifican toda la configuración subyacente y la gestión de bajo nivel de la infraestructura detrás de ella. Sin embargo, hay muchas cosas que deben hacerse para que la administración del clúster tenga una experiencia feliz en el viaje de un Administrador de Kubernetes.

Muchos conceptos con los que lidiar: namespaces, límites de recursos, cuotas, ingreso, servicios, rutas, crd… Cualquier ayuda que podamos obtener es bienvenida. Y con este propósito en mente, KubeEye ha nacido.

KubeEye es un proyecto de código abierto que ayuda a identificar algunos problemas en nuestros Clústeres de Kubernetes. Usando las palabras de sus creadores:

KubeEye tiene como objetivo encontrar varios problemas en Kubernetes, como la mala configuración de aplicaciones (usando Polaris), componentes de clúster no saludables y problemas de nodos (usando Node-Problem-Detector). Además de las reglas predefinidas, también admite reglas definidas por el usuario.

Así que podemos pensar en él como un compañero que está revisando el entorno para asegurarse de que todo esté bien configurado y saludable. Además, nos permite definir reglas personalizadas para asegurarnos de que todas las acciones que los diferentes equipos de desarrollo están realizando estén de acuerdo con los estándares predefinidos y las mejores prácticas.

Así que veamos cómo podemos incluir KubeEye para hacer una verificación de salud de nuestro entorno. Lo primero que necesitamos hacer es instalarlo. En este momento, KubeEye solo ofrece una versión para sistemas basados en Linux, por lo que si estás usando otros sistemas como yo, necesitas seguir otro enfoque y escribir los siguientes comandos:

git clone https://github.com/kubesphere/kubeeye.git
cd kubeeye
make install

Después de hacer eso, terminamos con un nuevo binario en nuestro PATH llamado `ke`, y este es el único componente necesario para trabajar con la aplicación. El segundo paso que necesitamos hacer para obtener más detalles sobre esos diagnósticos es instalar el componente detector de problemas de nodos.

Este componente es un componente instalado en cada nodo del clúster. Ayuda a hacer más visibles para las capas superiores los problemas relacionados con el comportamiento del clúster de Kubernetes. Este es un paso opcional, pero proporcionará datos más significativos, y para instalarlo, necesitamos ejecutar el siguiente comando.

ke install npd

Y ahora estamos listos para comenzar a verificar nuestro entorno, y el orden es tan fácil como este.

ke diag

Esto proporcionará una salida similar a esta que se compone de dos tablas diferentes. La primera se centrará en el Pod y los problemas y eventos planteados como parte del estado de la plataforma, y la otra se centrará en el resto de los elementos y tipos de objetos para los Clústeres de Kubernetes.

Verificación de Salud de Kubernetes: Cómo Hacerlo Más Simple
Salida del comando ke diag 

La tabla para los problemas a nivel de pod tiene los siguientes campos:

  • Namespace al que pertenece el pod.
  • Severidad del problema.
  • Nombre del Pod que es responsable del problema
  • Hora del Evento en la que se ha planteado este evento
  • Razón del problema
  • Mensaje con la descripción detallada del problema

La segunda tabla para los otros objetos tiene la siguiente estructura:

  • Namespace donde se despliega el objeto que tiene un problema que está siendo detectado.
  • Severidad del problema.
  • Nombre del componente
  • Tipo del componente
  • Hora en la que se ha planteado este problema
  • Mensaje con la descripción detallada del problema

La salida del comando también puede mostrar otras tablas si se detectan algunos problemas a nivel de nodo.


Hoy cubrimos un tema fascinante como es la Administración de Kubernetes e introducimos una nueva herramienta que ayuda en tu tarea diaria.

¡Realmente espero que esta herramienta pueda ser añadida a tu caja de herramientas y facilite el camino para una administración feliz y saludable del Clúster de Kubernetes!

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Prometheus Storage: Optimiza el uso del disco en tu implementación con estos trucos

Prometheus Storage: Optimiza el uso del disco en tu implementación con estos trucos

Descubre las propiedades que te permitirán un uso optimizado de tu almacenamiento en disco y ahorros al almacenar tus datos de monitoreo

Prometheus se ha convertido en un componente estándar en nuestras arquitecturas en la nube y el almacenamiento de Prometheus se está convirtiendo en un aspecto crítico. Así que voy a suponer que si estás leyendo esto ya sabes qué es Prometheus. Si este no es el caso, por favor tómate tu tiempo para echar un vistazo a otros artículos que he creado:

Sabemos que usualmente cuando monitoreamos usando Prometheus tenemos tantos exportadores disponibles a nuestra disposición y también que cada uno de ellos expone muchas métricas muy relevantes que necesitamos para rastrear todo lo que necesitamos y que lleva a un uso muy intensivo del almacenamiento disponible si no lo gestionamos adecuadamente.

Hay dos factores que afectan esto. El primero es optimizar el número de métricas que estamos almacenando y ya proporcionamos consejos para hacerlo en otros artículos como los que se muestran a continuación:

El otro es cuánto tiempo almacenamos las métricas llamado el “período de retención en Prometheus.” Y esta propiedad ha sufrido muchos cambios durante las diferentes versiones. Si te gustaría ver toda la historia, por favor echa un vistazo a este artículo de Robust Perception:

Las principales propiedades que puedes configurar son las siguientes:

  • storage.tsdb.retention.time: Número de días para almacenar las métricas por defecto a 15d. Esta propiedad reemplaza la obsoleta storage.tsdb.retention.
  • storage.tsdb.retention.size: Puedes especificar el límite de tamaño a utilizar. Este no es un límite estricto sino un mínimo, así que por favor define algún margen aquí. Unidades soportadas: B, KB, MB, GB, TB, PB, EB. Ej: “512MB”. Esta propiedad es experimental hasta ahora como puedes ver en la documentación oficial:

https://prometheus.io/docs/prometheus/latest/storage

¿Qué tal configurar esta configuración en el operador para Kubernetes? En ese caso, también tienes opciones similares disponibles en el archivo de configuración values.yaml para el chart como puedes ver en la imagen a continuación:

Prometheus Storage: Optimiza el uso del disco en tu implementación con estos trucos
values.yml para el Helm Chart del Operador de Prometheus

Esto debería ayudarte a obtener un despliegue optimizado de Prometheus que asegure todas las características que tiene Prometheus pero al mismo tiempo un uso óptimo de los recursos a tu disposición.

Además de eso, también deberías revisar las opciones de Servicio Gestionado que algunos proveedores tienen respecto a Prometheus, como los Servicios Gestionados de Amazon para Prometheus, como puedes ver en el enlace a continuación:

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Loki vs ELK: Una alternativa ligera al stack ELK

Loki vs ELK: Una alternativa ligera al stack ELK

Aprende sobre el nuevo sistema de agregación de logs escalable horizontalmente, altamente disponible y multi-inquilino inspirado en Prometheus que puede ser la mejor opción para tu arquitectura de registro

Loki vs ELK es algo que estás leyendo y escuchando cada vez más a menudo ya que desde hace algún tiempo hay un aumento en la disputa por convertirse en el estándar de facto para las arquitecturas de agregación de logs.

Cuando hablamos de Arquitectura Nativa de la Nube, la agregación de logs es algo clave que necesitas considerar. Las viejas prácticas que seguimos en el enfoque de máquinas virtuales on-premises para el registro ya no son válidas.

Ya cubrimos este tema en mi publicación anterior que te recomiendo echar un vistazo en caso de que no la hayas leído aún, pero este no es el tema de hoy.

Elasticsearch como el núcleo y las diferentes pilas derivadas como ELK/EFK han ganado popularidad en los últimos años, siendo prácticamente la opción predeterminada de código abierto cuando hablamos de agregación de logs y una de las opciones. Los principales proveedores de nube pública también han adoptado esta solución como parte de su propia oferta, como lo proporciona el Servicio de Elasticsearch de Amazon.

Pero Elasticsearch no es perfecto. Si ya lo has usado, probablemente lo sepas. Aún así, debido a que sus características son tan impresionantes, especialmente en las capacidades de búsqueda e indexación, ha sido el tipo de líder hoy en día. Pero otros temas como el uso del almacenamiento, la cantidad de poder que necesitas para manejarlo y la arquitectura con diferentes tipos de nodos (maestro, datos, ingestor) aumentan su complejidad para casos cuando necesitamos algo más pequeño.

Y para llenar este vacío es donde llega nuestro personaje principal para la publicación de hoy: Loki o Grafana Loki.

Loki vs ELK: Una alternativa ligera al stack ELK
Logo de Grafana Loki de https://grafana.com/oss/loki/

Loki es un sistema de gestión de logs creado como parte del proyecto Grafana, y ha sido creado con un enfoque diferente en mente que Elasticsearch.

Loki es un sistema de agregación de logs escalable horizontalmente, altamente disponible y multi-inquilino inspirado en Prometheus. Está diseñado para ser muy rentable y fácil de operar. No indexa el contenido de los logs, sino un conjunto de etiquetas para cada flujo de logs.

Así que, como podemos leer en la definición de su propia página arriba, cubre varios temas interesantes en comparación con Elasticsearch:

  • En primer lugar, aborda algunos de los puntos de dolor habituales para los clientes de ELK: Es muy rentable y fácil de operar.
  • Claramente dice que el enfoque no es el mismo que ELK, no vas a tener un índice completo de la carga útil para los eventos, sino que se basa en diferentes etiquetas que puedes definir para cada flujo de logs.
  • Prometheus inspira eso, lo cual es crítico porque permitió la idea de usar trazas de logs como métricas para potenciar nuestras soluciones de monitoreo.

Comencemos con las preguntas iniciales cuando mostramos una nueva tecnología interesante y nos gustaría comenzar a probarla.

¿Cómo puedo instalar Loki?

Loki se distribuye en diferentes versiones para ser instalado en tu entorno de la manera que lo necesites.

  • SaaS: proporcionado como parte de la solución de alojamiento de Grafana Cloud.
  • On-Premises: Proporcionado como un binario normal para descargar y ejecutar en modo on-premises.
  • Nube: Proporcionado como una imagen de Docker o incluso un Helm Chart para ser desplegado en tu entorno basado en Kubernetes.

Los equipos de GrafanaLabs también proporcionan Soporte Empresarial para Loki si deseas usarlo en modo de producción en tu empresa. Aún así, al mismo tiempo, todo el código está licenciado usando la Licencia Apache 2.0, por lo que puedes echar un vistazo a todo el código y contribuir a él.

¿Cómo funciona Loki?

Loki vs ELK: Una alternativa ligera al stack ELK
Arquitectura de alto nivel de Loki de https://grafana.com/blog/2018/12/12/loki-prometheus-inspired-open-source-logging-for-cloud-natives/

En cuanto a la arquitectura, es muy similar a la pila ELK/EFK y sigue el mismo enfoque de “coleccionistas” e “indexadores” como tiene ELK:

  • Loki en sí mismo es el nodo central de la arquitectura responsable de almacenar las trazas de logs y sus etiquetas y proporciona una API para buscar entre ellas basándose en su propio lenguaje LogQL (un enfoque similar al PromQL de Prometheus).
  • promtail es el componente agente que se ejecuta en el borde obteniendo todas esas trazas de logs que necesitamos que pueden estar ejecutándose en una máquina on-prem o en un modo DaemonSet en nuestro propio clúster de Kubernetes. Desempeña el mismo papel que Logstash/Fluent-bit/Fluentd en la pila ELK/EFK. Promtail proporciona el modo de plugin habitual para filtrar y transformar nuestras trazas de logs como lo hacen las otras soluciones. Al mismo tiempo, proporciona una característica interesante para convertir esas trazas de logs en métricas de Prometheus que pueden ser recolectadas directamente por tu servidor Prometheus.
  • Grafana es la interfaz de usuario para toda la pila y desempeña un papel similar al de Kibana en la pila ELK/EFK. Grafana, entre otros plugins, proporciona integración directa con Loki como una fuente de datos para explorar esas trazas e incluirlas en los paneles.

Resumen

Grafana Loki puede ser una gran solución para tu arquitectura de registro para cubrir dos puntos: Proporcionar una solución de agregación de logs ligera para tu entorno y al mismo tiempo habilitar tus trazas de logs como una fuente para tus métricas, permitiéndote crear métricas detalladas, más orientadas al negocio que se utilizan en tus paneles y tus sistemas de monitoreo.

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?

Descubre SARChart y kSAR como utilidades críticas para ser parte de tu cinturón de herramientas para administración o resolución de problemas

Hubo un tiempo en que no teníamos proveedores de nube pública que nos proporcionaran una variedad de tipos de servicios y toda una plataforma y experiencia unificada, cubriendo todos los aspectos de nuestras necesidades técnicas cuando hablábamos de un entorno de TI y las métricas de sysstat eran clave allí.

Hubo un tiempo en que AWS Cloud Watch, Azure Monitor, Prometheus no existían, y necesitábamos lidiar con servidores Linux sin un portal completo que proporcionara todas las métricas que podríamos necesitar.

Hubo un tiempo… que todavía es el presente para muchos clientes y organizaciones en todo el mundo y aún necesitan lidiar con esta situación, y probablemente te enfrentes a esta situación ahora o incluso en el futuro. Así que, veamos qué podemos hacer al respecto.

Presentando sysstat

Durante varias décadas, la forma estándar de extraer las métricas de uso de un servidor Linux fue sysstat. Basado en las palabras de su página web oficial, esto es lo que es sysstat:

Las utilidades sysstat son una colección de herramientas de monitoreo de rendimiento para Linux. Estas incluyen sar, sadf, mpstat, iostat, tapestat, pidstat, cifsiostat y herramientas sa 

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Sysstat es un software antiguo pero confiable que su propietario continúa actualizando incluso hoy… pero manteniendo la misma página web desde el principio 🙂

Sysstat es antiguo pero poderoso, y tiene tantas opciones que me han salvado la vida con muchos clientes y proporcionado mucha información útil que necesitaba en ese momento. Pero hoy, voy a hablar sobre una utilidad específica de todo el conjunto, que es sar.

sar es el comando para poder consultar las métricas de rendimiento de una máquina existente. Simplemente escribiendo el comando sar es suficiente para comenzar a ver cosas impresionantes. Eso te dará las métricas de CPU para todo el día para cada una de las CPUs que tiene tu máquina y también se dividirá dependiendo del tipo de uso (usuario, sistema, inactivo, todo).

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Ejecución del comando sar en una máquina local 

Pero estas métricas no son lo único que puedes obtener. Otras opciones disponibles

  • sar -r: Proporciona métricas de memoria
  • sar -q: Proporciona las métricas de carga.
  • sar -n: Proporciona las métricas de red.
  • sar -A: Proporciona TODAS las métricas.
  • sar -f /var/log/sysstat/sa[día-del-mes]: Proporcionará métricas para el día del mes en lugar del día actual.

Hay muchas más opciones que puedes usar en tu día a día, así que si necesitas algo concreto, echa un vistazo a la página del manual para el comando sar:

Pero todos somos personas visuales, ¿verdad? Es cierto que ver tendencias y evoluciones es más complejo en modo texto y también ver solo datos diarios a la vez. Así que echa un vistazo a las opciones para manejar ese desafío:

kSAR

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Logo de la aplicación kSAR (https://sourceforge.net/projects/ksar/)

Frontend desarrollado en Java usando la biblioteca Swing para representar visualmente los datos de sar. Es portátil, por lo que necesitas el archivo JAR para ejecutarlo. Y puedes invocarlo de varias maneras:

  • Proporcionando el archivo que obtuviste de una máquina en la que ejecutaste el comando sar.
  • Conectando mediante SSH a una máquina remota y ejecutando el comando que necesitas.
Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Visualización gráfica de las métricas de sar usando kSAR

SARChart

¿Qué pasa cuando estás en una máquina en la que no tienes los derechos para instalar ninguna aplicación, incluso una portátil como kSAR, o tal vez solo tienes tu tableta disponible? En ese caso, tenemos SARChart.

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Página de inicio de la aplicación SARChart (https://sarchart.dotsuresh.com/)

SARChart es una aplicación web que proporciona un análisis gráfico de los archivos sar. Así que solo necesitas subir el archivo para obtener un análisis gráfico completo y bien presentado de tus datos cubriendo todos sus aspectos. Además, todo el trabajo se realiza a nivel del cliente sin enviar ninguno de tus datos a ningún servidor.

Métricas y herramientas de Sysstat: ¿Cómo obtener un análisis gráfico impresionante?
Análisis de uso de CPU proporcionado por SARChart

Resumen

Espero que encuentres estas herramientas interesantes si no las conocías, y también espero que puedan ayudarte con tu trabajo diario o al menos ser parte de tu conjunto de herramientas para estar a tu disposición cuando las necesites.

Servicio AWS Prometheus para Proporcionar Más Disponibilidad a su Solución de Monitoreo

Servicio AWS Prometheus para Proporcionar Más Disponibilidad a su Solución de Monitoreo

Aprende qué proporciona el Servicio Administrado de Amazon para Prometheus y cómo puedes beneficiarte de él.

El monitoreo es uno de los temas candentes cuando hablamos de arquitecturas nativas de la nube. Prometheus es un proyecto de código abierto graduado de la Cloud Native Computing Foundation (CNCF) y una de las soluciones estándar de la industria cuando se trata de monitorear tu implementación nativa de la nube, especialmente cuando Kubernetes está involucrado.

Siguiendo su propia filosofía de proporcionar un servicio administrado para algunos de los proyectos de código abierto más utilizados pero totalmente integrado con el ecosistema de AWS, AWS lanza una vista previa general (en el momento de escribir este artículo): Servicio Administrado de Amazon para Prometheus (AMP).

Lo primero es definir qué es el Servicio Administrado de Amazon para Prometheus y qué características proporciona. Así que, esta es la definición de Amazon del servicio:

Un servicio de monitoreo totalmente administrado compatible con Prometheus que facilita el monitoreo de aplicaciones en contenedores de manera segura y a escala.

Y me gustaría dedicar algo de tiempo a algunas partes de esta oración.

  • Servicio totalmente administrado: Entonces, esto será alojado y manejado por Amazon, y solo vamos a interactuar con él usando API como lo hacemos con otros servicios de Amazon como EKS, RDS, MSK, SQS/SNS, y así sucesivamente.
  • Compatible con Prometheus: Entonces, eso significa que incluso si esta no es una instalación pura de Prometheus, la API será compatible. Así que los clientes de Prometheus que pueden usar Grafana u otros para obtener la información de Prometheus funcionarán sin cambiar sus interfaces.
  • Servicio a escala: Amazon, como parte del servicio administrado, se encargará de la escalabilidad de la solución. No necesitas definir un tipo de instancia o cuánta RAM o CPU necesitas. Esto será manejado por AWS.

Entonces, eso suena perfecto. Así que puedes pensar que vas a eliminar tu servidor de Prometheus, y comenzará a usar este servicio. Tal vez incluso estés escribiendo algo como helm delete prom… ¡ESPERA ESPERA!

Porque en este punto, esto no va a reemplazar tu servidor local de Prometheus, pero permitirá la integración con él. Así que, eso significa que tu servidor de Prometheus actuará como un recolector para toda la solución de monitoreo escalable que AMP está proporcionando, algo como puedes ver en la imagen a continuación:

Servicio AWS Prometheus para Proporcionar Más Disponibilidad a su Solución de Monitoreo
Arquitectura de Referencia para el Servicio de Prometheus de Amazon

Entonces, todavía vas a necesitar un servidor de Prometheus, eso es correcto, pero toda la complejidad se evitará y se aprovechará en el servicio administrado: La configuración de almacenamiento, alta disponibilidad, optimización de API, y así sucesivamente, se te proporcionará directamente.

Ingesta de información en el Servicio Administrado de Amazon para Prometheus

En este momento, hay dos formas de ingresar datos en el Servicio de Prometheus de Amazon:

  • Desde un servidor de Prometheus existente usando la capacidad y configuración de remote_write, lo que significa que cada serie que es recolectada por el Prometheus local será enviada al Servicio de Prometheus de Amazon.
  • Usando AWS Distro para OpenTelemetry para integrarse con este servicio usando el Receptor de Prometheus y los componentes Exportador de Escritura Remota de AWS Prometheus para obtener eso.

Resumen

Así que esta es una forma de proporcionar una instalación de nivel empresarial aprovechando todo el conocimiento que AWS tiene al alojar y gestionar esta solución a escala y optimizada en términos de rendimiento. Puedes centrarte en los componentes que necesitas para obtener las métricas ingresadas en el servicio.

Estoy seguro de que este no será el último movimiento de AWS en temas de observabilidad y gestión de métricas. Estoy seguro de que continuarán proporcionando más herramientas a las manos de los desarrolladores y arquitectos para definir soluciones optimizadas tan fácilmente como sea posible.

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Prometheus Storage: ¿Cómo optimizar el uso del disco?

Prometheus Storage: ¿Cómo optimizar el uso del disco?

Aprende algunos trucos para analizar y optimizar el uso que estás haciendo de la TSDB y ahorrar dinero en tu implementación en la nube.

En publicaciones anteriores, discutimos cómo funcionaba la capa de almacenamiento para Prometheus y cuán efectiva era. Pero en los tiempos actuales, estamos en la era de la computación en la nube y sabemos que cada optimización técnica es también una optimización de costos, y es por eso que necesitamos ser muy diligentes con cualquier opción que usemos en cuanto a optimización.

Sabemos que usualmente cuando monitoreamos usando Prometheus tenemos muchos exportadores disponibles a nuestra disposición y también que cada uno de ellos expone muchas métricas muy relevantes que necesitamos para rastrear todo lo que necesitamos. Pero también, debemos ser conscientes de que hay métricas que no necesitamos en este momento o que no planeamos usar. Entonces, si no planeamos usarlas, ¿por qué queremos desperdiciar espacio en disco almacenándolas?

Así que, comencemos echando un vistazo a uno de los exportadores que tenemos en nuestro sistema. En mi caso, me gustaría usar una Aplicación de Contenedor BusinessWorks que expone métricas sobre su utilización. Si revisas su punto de acceso de métricas podrías ver algo como esto:

# HELP jvm_info Información de la versión de JVM
# TYPE jvm_info gauge
jvm_info{version="1.8.0_221-b27",vendor="Oracle Corporation",runtime="Java(TM) SE Runtime Environment",} 1.0
# HELP jvm_memory_bytes_used Bytes usados de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_used gauge
jvm_memory_bytes_used{area="heap",} 1.0318492E8
jvm_memory_bytes_used{area="nonheap",} 1.52094712E8
# HELP jvm_memory_bytes_committed Bytes comprometidos de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_committed gauge
jvm_memory_bytes_committed{area="heap",} 1.35266304E8
jvm_memory_bytes_committed{area="nonheap",} 1.71302912E8
# HELP jvm_memory_bytes_max Máximo de bytes de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_max gauge
jvm_memory_bytes_max{area="heap",} 1.073741824E9
jvm_memory_bytes_max{area="nonheap",} -1.0
# HELP jvm_memory_bytes_init Bytes iniciales de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_init gauge
jvm_memory_bytes_init{area="heap",} 1.34217728E8
jvm_memory_bytes_init{area="nonheap",} 2555904.0
# HELP jvm_memory_pool_bytes_used Bytes usados de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_used gauge
jvm_memory_pool_bytes_used{pool="Code Cache",} 3.3337536E7
jvm_memory_pool_bytes_used{pool="Metaspace",} 1.04914136E8
jvm_memory_pool_bytes_used{pool="Compressed Class Space",} 1.384304E7
jvm_memory_pool_bytes_used{pool="G1 Eden Space",} 3.3554432E7
jvm_memory_pool_bytes_used{pool="G1 Survivor Space",} 1048576.0
jvm_memory_pool_bytes_used{pool="G1 Old Gen",} 6.8581912E7
# HELP jvm_memory_pool_bytes_committed Bytes comprometidos de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_committed gauge
jvm_memory_pool_bytes_committed{pool="Code Cache",} 3.3619968E7
jvm_memory_pool_bytes_committed{pool="Metaspace",} 1.19697408E8
jvm_memory_pool_bytes_committed{pool="Compressed Class Space",} 1.7985536E7
jvm_memory_pool_bytes_committed{pool="G1 Eden Space",} 4.6137344E7
jvm_memory_pool_bytes_committed{pool="G1 Survivor Space",} 1048576.0
jvm_memory_pool_bytes_committed{pool="G1 Old Gen",} 8.8080384E7
# HELP jvm_memory_pool_bytes_max Máximo de bytes de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_max gauge
jvm_memory_pool_bytes_max{pool="Code Cache",} 2.5165824E8
jvm_memory_pool_bytes_max{pool="Metaspace",} -1.0
jvm_memory_pool_bytes_max{pool="Compressed Class Space",} 1.073741824E9
jvm_memory_pool_bytes_max{pool="G1 Eden Space",} -1.0
jvm_memory_pool_bytes_max{pool="G1 Survivor Space",} -1.0
jvm_memory_pool_bytes_max{pool="G1 Old Gen",} 1.073741824E9
# HELP jvm_memory_pool_bytes_init Bytes iniciales de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_init gauge
jvm_memory_pool_bytes_init{pool="Code Cache",} 2555904.0
jvm_memory_pool_bytes_init{pool="Metaspace",} 0.0
jvm_memory_pool_bytes_init{pool="Compressed Class Space",} 0.0
jvm_memory_pool_bytes_init{pool="G1 Eden Space",} 7340032.0
jvm_memory_pool_bytes_init{pool="G1 Survivor Space",} 0.0
jvm_memory_pool_bytes_init{pool="G1 Old Gen",} 1.26877696E8
# HELP jvm_buffer_pool_used_bytes Bytes usados de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_used_bytes gauge
jvm_buffer_pool_used_bytes{pool="direct",} 148590.0
jvm_buffer_pool_used_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_capacity_bytes Capacidad en bytes de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_capacity_bytes gauge
jvm_buffer_pool_capacity_bytes{pool="direct",} 148590.0
jvm_buffer_pool_capacity_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_used_buffers Buffers usados de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_used_buffers gauge
jvm_buffer_pool_used_buffers{pool="direct",} 19.0
jvm_buffer_pool_used_buffers{pool="mapped",} 0.0
# HELP jvm_classes_loaded El número de clases que están actualmente cargadas en la JVM
# TYPE jvm_classes_loaded gauge
jvm_classes_loaded 16993.0
# HELP jvm_classes_loaded_total El número total de clases que han sido cargadas desde que la JVM comenzó a ejecutarse
# TYPE jvm_classes_loaded_total counter
jvm_classes_loaded_total 17041.0
# HELP jvm_classes_unloaded_total El número total de clases que han sido descargadas desde que la JVM comenzó a ejecutarse
# TYPE jvm_classes_unloaded_total counter
jvm_classes_unloaded_total 48.0
# HELP bwce_activity_stats_list Lista de estadísticas de actividad BWCE
# TYPE bwce_activity_stats_list gauge
# HELP bwce_activity_counter_list Lista de contadores relacionados con la actividad BWCE
# TYPE bwce_activity_counter_list gauge
# HELP all_activity_events_count Conteo de todos los eventos de actividad BWCE por estado
# TYPE all_activity_events_count counter
all_activity_events_count{StateName="CANCELLED",} 0.0
all_activity_events_count{StateName="COMPLETED",} 0.0
all_activity_events_count{StateName="STARTED",} 0.0
all_activity_events_count{StateName="FAULTED",} 0.0
# HELP activity_events_count Conteo de todos los eventos de actividad BWCE por proceso, estado de actividad
# TYPE activity_events_count counter
# HELP activity_total_evaltime_count Tiempo total de evaluación de actividad BWCE por proceso y actividad
# TYPE activity_total_evaltime_count counter
# HELP activity_total_duration_count Tiempo total de duración de actividad BWCE por proceso y actividad
# TYPE activity_total_duration_count counter
# HELP bwpartner_instance:total_request Solicitud total para la invocación del socio que se mapeó desde las actividades
# TYPE bwpartner_instance:total_request counter
# HELP bwpartner_instance:total_duration_ms Duración total para la invocación del socio que se mapeó desde las actividades (ejecución o latencia)
# TYPE bwpartner_instance:total_duration_ms counter
# HELP bwce_process_stats Lista de estadísticas de proceso BWCE
# TYPE bwce_process_stats gauge
# HELP bwce_process_counter_list Lista de contadores relacionados con el proceso BWCE
# TYPE bwce_process_counter_list gauge
# HELP all_process_events_count Conteo de todos los eventos de proceso BWCE por estado
# TYPE all_process_events_count counter
all_process_events_count{StateName="CANCELLED",} 0.0
all_process_events_count{StateName="COMPLETED",} 0.0
all_process_events_count{StateName="STARTED",} 0.0
all_process_events_count{StateName="FAULTED",} 0.0
# HELP process_events_count Conteo de eventos de proceso BWCE por operación
# TYPE process_events_count counter
# HELP process_duration_seconds_total Duración de eventos de proceso BWCE por operación en segundos
# TYPE process_duration_seconds_total counter
# HELP process_duration_milliseconds_total Duración de eventos de proceso BWCE por operación en milisegundos
# TYPE process_duration_milliseconds_total counter
# HELP bwdefinitions:partner Conteo de eventos de proceso BWCE por operación
# TYPE bwdefinitions:partner counter
bwdefinitions:partner{ProcessName="t1.module.item.getTransactionData",ActivityName="FTLPublisher",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="TransactionService",PartnerOperation="GetTransactionsOperation",Location="internal",PartnerMiddleware="MW",} 1.0
bwdefinitions:partner{ProcessName=" t1.module.item.auditProcess",ActivityName="KafkaSendMessage",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="AuditService",PartnerOperation="AuditOperation",Location="internal",PartnerMiddleware="MW",} 1.0
bwdefinitions:partner{ProcessName="t1.module.item.getCustomerData",ActivityName="JMSRequestReply",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="CustomerService",PartnerOperation="GetCustomerDetailsOperation",Location="internal",PartnerMiddleware="MW",} 1.0
# HELP bwdefinitions:binding Repositorio de tiempo de diseño BW - definición de enlace/transporte
# TYPE bwdefinitions:binding counter
bwdefinitions:binding{ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInterface="GetCustomer360:GetDataOperation",Binding="/customer",Transport="HTTP",} 1.0
# HELP bwdefinitions:service Repositorio de tiempo de diseño BW - definición de servicio
# TYPE bwdefinitions:service counter
bwdefinitions:service{ProcessName="t1.module.sub.item.getCustomerData",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.sub.item.auditProcess",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.sub.orchestratorSubFlow",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.Process",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
# HELP bwdefinitions:gateway Repositorio de tiempo de diseño BW - definición de puerta de enlace
# TYPE bwdefinitions:gateway counter
bwdefinitions:gateway{ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",Endpoint="bwce-demo-mon-orchestrator-bwce",InteractionType="ISTIO",} 1.0
# HELP process_cpu_seconds_total Tiempo total de usuario y sistema de CPU gastado en segundos.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 1956.86
# HELP process_start_time_seconds Hora de inicio del proceso desde la época de Unix en segundos.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.604712447107E9
# HELP process_open_fds Número de descriptores de archivo abiertos.
# TYPE process_open_fds gauge
process_open_fds 763.0
# HELP process_max_fds Número máximo de descriptores de archivo abiertos.
# TYPE process_max_fds gauge
process_max_fds 1048576.0
# HELP process_virtual_memory_bytes Tamaño de la memoria virtual en bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 3.046207488E9
# HELP process_resident_memory_bytes Tamaño de la memoria residente en bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 4.2151936E8
# HELP jvm_gc_collection_seconds Tiempo gastado en un recolector de basura JVM dado en segundos.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc="G1 Young Generation",} 540.0
jvm_gc_collection_seconds_sum{gc="G1 Young Generation",} 4.754
jvm_gc_collection_seconds_count{gc="G1 Old Generation",} 2.0
jvm_gc_collection_seconds_sum{gc="G1 Old Generation",} 0.563
# HELP jvm_threads_current Conteo actual de hilos de una JVM
# TYPE jvm_threads_current gauge
jvm_threads_current 98.0
# HELP jvm_threads_daemon Conteo de hilos daemon de una JVM
# TYPE jvm_threads_daemon gauge
jvm_threads_daemon 43.0
# HELP jvm_threads_peak Conteo máximo de hilos de una JVM
# TYPE jvm_threads_peak gauge
jvm_threads_peak 98.0
# HELP jvm_threads_started_total Conteo de hilos iniciados de una JVM
# TYPE jvm_threads_started_total counter
jvm_threads_started_total 109.0
# HELP jvm_threads_deadlocked Ciclos de hilos JVM que están en deadlock esperando adquirir monitores de objetos o sincronizadores propios
# TYPE jvm_threads_deadlocked gauge
jvm_threads_deadlocked 0.0
# HELP jvm_threads_deadlocked_monitor Ciclos de hilos JVM que están en deadlock esperando adquirir monitores de objetos
# TYPE jvm_threads_deadlocked_monitor gauge
jvm_threads_deadlocked_monitor 0.0

Como puedes ver, muchas métricas, pero tengo que ser honesto, no estoy usando la mayoría de ellas en mis paneles y para generar mis alertas. Puedo usar las métricas relacionadas con el rendimiento de la aplicación para cada uno de los procesos de BusinessWorks y sus actividades, también el rendimiento de la memoria JVM y el número de hilos, pero cosas como cómo está funcionando el GC de la JVM para cada una de las capas de la JVM (G1 Young Generation, G1 Old Generation) no las estoy usando en absoluto.

Entonces, si muestro el mismo punto de acceso de métricas destacando las cosas que no estoy usando, sería algo como esto:

# HELP jvm_info Información de la versión de JVM
# TYPE jvm_info gauge
jvm_info{version="1.8.0_221-b27",vendor="Oracle Corporation",runtime="Java(TM) SE Runtime Environment",} 1.0

# HELP jvm_memory_bytes_used Bytes usados de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_used gauge
jvm_memory_bytes_used{area="heap",} 1.0318492E8
jvm_memory_bytes_used{area="nonheap",} 1.52094712E8
# HELP jvm_memory_bytes_committed Bytes comprometidos de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_committed gauge
jvm_memory_bytes_committed{area="heap",} 1.35266304E8
jvm_memory_bytes_committed{area="nonheap",} 1.71302912E8
# HELP jvm_memory_bytes_max Máximo de bytes de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_max gauge
jvm_memory_bytes_max{area="heap",} 1.073741824E9
jvm_memory_bytes_max{area="nonheap",} -1.0
# HELP jvm_memory_bytes_init Bytes iniciales de un área de memoria JVM dada.
# TYPE jvm_memory_bytes_init gauge
jvm_memory_bytes_init{area="heap",} 1.34217728E8
jvm_memory_bytes_init{area="nonheap",} 2555904.0

# HELP jvm_memory_pool_bytes_used Bytes usados de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_used gauge
jvm_memory_pool_bytes_used{pool="Code Cache",} 3.3337536E7
jvm_memory_pool_bytes_used{pool="Metaspace",} 1.04914136E8
jvm_memory_pool_bytes_used{pool="Compressed Class Space",} 1.384304E7
jvm_memory_pool_bytes_used{pool="G1 Eden Space",} 3.3554432E7
jvm_memory_pool_bytes_used{pool="G1 Survivor Space",} 1048576.0
jvm_memory_pool_bytes_used{pool="G1 Old Gen",} 6.8581912E7
# HELP jvm_memory_pool_bytes_committed Bytes comprometidos de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_committed gauge
jvm_memory_pool_bytes_committed{pool="Code Cache",} 3.3619968E7
jvm_memory_pool_bytes_committed{pool="Metaspace",} 1.19697408E8
jvm_memory_pool_bytes_committed{pool="Compressed Class Space",} 1.7985536E7
jvm_memory_pool_bytes_committed{pool="G1 Eden Space",} 4.6137344E7
jvm_memory_pool_bytes_committed{pool="G1 Survivor Space",} 1048576.0
jvm_memory_pool_bytes_committed{pool="G1 Old Gen",} 8.8080384E7
# HELP jvm_memory_pool_bytes_max Máximo de bytes de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_max gauge
jvm_memory_pool_bytes_max{pool="Code Cache",} 2.5165824E8
jvm_memory_pool_bytes_max{pool="Metaspace",} -1.0
jvm_memory_pool_bytes_max{pool="Compressed Class Space",} 1.073741824E9
jvm_memory_pool_bytes_max{pool="G1 Eden Space",} -1.0
jvm_memory_pool_bytes_max{pool="G1 Survivor Space",} -1.0
jvm_memory_pool_bytes_max{pool="G1 Old Gen",} 1.073741824E9
# HELP jvm_memory_pool_bytes_init Bytes iniciales de un pool de memoria JVM dado.
# TYPE jvm_memory_pool_bytes_init gauge
jvm_memory_pool_bytes_init{pool="Code Cache",} 2555904.0
jvm_memory_pool_bytes_init{pool="Metaspace",} 0.0
jvm_memory_pool_bytes_init{pool="Compressed Class Space",} 0.0
jvm_memory_pool_bytes_init{pool="G1 Eden Space",} 7340032.0
jvm_memory_pool_bytes_init{pool="G1 Survivor Space",} 0.0
jvm_memory_pool_bytes_init{pool="G1 Old Gen",} 1.26877696E8
# HELP jvm_buffer_pool_used_bytes Bytes usados de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_used_bytes gauge
jvm_buffer_pool_used_bytes{pool="direct",} 148590.0
jvm_buffer_pool_used_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_capacity_bytes Capacidad en bytes de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_capacity_bytes gauge
jvm_buffer_pool_capacity_bytes{pool="direct",} 148590.0
jvm_buffer_pool_capacity_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_used_buffers Buffers usados de un pool de buffer JVM dado.
# TYPE jvm_buffer_pool_used_buffers gauge
jvm_buffer_pool_used_buffers{pool="direct",} 19.0
jvm_buffer_pool_used_buffers{pool="mapped",} 0.0
# HELP jvm_classes_loaded El número de clases que están actualmente cargadas en la JVM
# TYPE jvm_classes_loaded gauge
jvm_classes_loaded 16993.0
# HELP jvm_classes_loaded_total El número total de clases que han sido cargadas desde que la JVM comenzó a ejecutarse
# TYPE jvm_classes_loaded_total counter
jvm_classes_loaded_total 17041.0
# HELP jvm_classes_unloaded_total El número total de clases que han sido descargadas desde que la JVM comenzó a ejecutarse
# TYPE jvm_classes_unloaded_total counter
jvm_classes_unloaded_total 48.0

# HELP bwce_activity_stats_list Lista de estadísticas de actividad BWCE
# TYPE bwce_activity_stats_list gauge
# HELP bwce_activity_counter_list Lista de contadores relacionados con la actividad BWCE
# TYPE bwce_activity_counter_list gauge
# HELP all_activity_events_count Conteo de todos los eventos de actividad BWCE por estado
# TYPE all_activity_events_count counter
all_activity_events_count{StateName="CANCELLED",} 0.0
all_activity_events_count{StateName="COMPLETED",} 0.0
all_activity_events_count{StateName="STARTED",} 0.0
all_activity_events_count{StateName="FAULTED",} 0.0
# HELP activity_events_count Conteo de todos los eventos de actividad BWCE por proceso, estado de actividad
# TYPE activity_events_count counter
# HELP activity_total_evaltime_count Tiempo total de evaluación de actividad BWCE por proceso y actividad
# TYPE activity_total_evaltime_count counter
# HELP activity_total_duration_count Tiempo total de duración de actividad BWCE por proceso y actividad
# TYPE activity_total_duration_count counter
# HELP bwpartner_instance:total_request Solicitud total para la invocación del socio que se mapeó desde las actividades
# TYPE bwpartner_instance:total_request counter
# HELP bwpartner_instance:total_duration_ms Duración total para la invocación del socio que se mapeó desde las actividades (ejecución o latencia)
# TYPE bwpartner_instance:total_duration_ms counter
# HELP bwce_process_stats Lista de estadísticas de proceso BWCE
# TYPE bwce_process_stats gauge
# HELP bwce_process_counter_list Lista de contadores relacionados con el proceso BWCE
# TYPE bwce_process_counter_list gauge
# HELP all_process_events_count Conteo de todos los eventos de proceso BWCE por estado
# TYPE all_process_events_count counter
all_process_events_count{StateName="CANCELLED",} 0.0
all_process_events_count{StateName="COMPLETED",} 0.0
all_process_events_count{StateName="STARTED",} 0.0
all_process_events_count{StateName="FAULTED",} 0.0
# HELP process_events_count Conteo de eventos de proceso BWCE por operación
# TYPE process_events_count counter
# HELP process_duration_seconds_total Duración de eventos de proceso BWCE por operación en segundos
# TYPE process_duration_seconds_total counter
# HELP process_duration_milliseconds_total Duración de eventos de proceso BWCE por operación en milisegundos
# TYPE process_duration_milliseconds_total counter
# HELP bwdefinitions:partner Conteo de eventos de proceso BWCE por operación
# TYPE bwdefinitions:partner counter
bwdefinitions:partner{ProcessName="t1.module.item.getTransactionData",ActivityName="FTLPublisher",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="TransactionService",PartnerOperation="GetTransactionsOperation",Location="internal",PartnerMiddleware="MW",} 1.0
bwdefinitions:partner{ProcessName=" t1.module.item.auditProcess",ActivityName="KafkaSendMessage",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="AuditService",PartnerOperation="AuditOperation",Location="internal",PartnerMiddleware="MW",} 1.0
bwdefinitions:partner{ProcessName="t1.module.item.getCustomerData",ActivityName="JMSRequestReply",ServiceName="GetCustomer360",OperationName="GetDataOperation",PartnerService="CustomerService",PartnerOperation="GetCustomerDetailsOperation",Location="internal",PartnerMiddleware="MW",} 1.0
# HELP bwdefinitions:binding Repositorio de tiempo de diseño BW - definición de enlace/transporte
# TYPE bwdefinitions:binding counter
bwdefinitions:binding{ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInterface="GetCustomer360:GetDataOperation",Binding="/customer",Transport="HTTP",} 1.0
# HELP bwdefinitions:service Repositorio de tiempo de diseño BW - definición de servicio
# TYPE bwdefinitions:service counter
bwdefinitions:service{ProcessName="t1.module.sub.item.getCustomerData",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.sub.item.auditProcess",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.sub.orchestratorSubFlow",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
bwdefinitions:service{ProcessName="t1.module.Process",ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",} 1.0
# HELP bwdefinitions:gateway Repositorio de tiempo de diseño BW - definición de puerta de enlace
# TYPE bwdefinitions:gateway counter
bwdefinitions:gateway{ServiceName="GetCustomer360",OperationName="GetDataOperation",ServiceInstance="GetCustomer360:GetDataOperation",Endpoint="bwce-demo-mon-orchestrator-bwce",InteractionType="ISTIO",} 1.0
# HELP process_cpu_seconds_total Tiempo total de usuario y sistema de CPU gastado en segundos.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 1956.86
# HELP process_start_time_seconds Hora de inicio del proceso desde la época de Unix en segundos.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.604712447107E9
# HELP process_open_fds Número de descriptores de archivo abiertos.
# TYPE process_open_fds gauge
process_open_fds 763.0
# HELP process_max_fds Número máximo de descriptores de archivo abiertos.
# TYPE process_max_fds gauge
process_max_fds 1048576.0
# HELP process_virtual_memory_bytes Tamaño de la memoria virtual en bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 3.046207488E9
# HELP process_resident_memory_bytes Tamaño de la memoria residente en bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 4.2151936E8
# HELP jvm_gc_collection_seconds Tiempo gastado en un recolector de basura JVM dado en segundos.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc="G1 Young Generation",} 540.0
jvm_gc_collection_seconds_sum{gc="G1 Young Generation",} 4.754
jvm_gc_collection_seconds_count{gc="G1 Old Generation",} 2.0
jvm_gc_collection_seconds_sum{gc="G1 Old Generation",} 0.563

# HELP jvm_threads_current Conteo actual de hilos de una JVM
# TYPE jvm_threads_current gauge
jvm_threads_current 98.0
# HELP jvm_threads_daemon Conteo de hilos daemon de una JVM
# TYPE jvm_threads_daemon gauge
jvm_threads_daemon 43.0
# HELP jvm_threads_peak Conteo máximo de hilos de una JVM
# TYPE jvm_threads_peak gauge
jvm_threads_peak 98.0
# HELP jvm_threads_started_total Conteo de hilos iniciados de una JVM
# TYPE jvm_threads_started_total counter
jvm_threads_started_total 109.0
# HELP jvm_threads_deadlocked Ciclos de hilos JVM que están en deadlock esperando adquirir monitores de objetos o sincronizadores propios
# TYPE jvm_threads_deadlocked gauge
jvm_threads_deadlocked 0.0
# HELP jvm_threads_deadlocked_monitor Ciclos de hilos JVM que están en deadlock esperando adquirir monitores de objetos
# TYPE jvm_threads_deadlocked_monitor gauge
jvm_threads_deadlocked_monitor 0.0

Entonces, puede ser un 50% de la respuesta del punto de acceso de métricas la parte que no estoy usando, entonces, ¿por qué estoy usando espacio en disco que estoy pagando para almacenarlo? Y esto es solo para un «exportador crítico», uno que trato de usar tanta información como sea posible, pero piensa en cuántos exportadores tienes y cuánta información usas para cada uno de ellos.

Ok, entonces ahora el propósito y la motivación de esta publicación están claros, pero ¿qué podemos hacer al respecto?

Descubriendo la API REST

Prometheus tiene una increíble API REST para exponer toda la información que puedas desear. Si alguna vez has usado la Interfaz Gráfica para Prometheus (mostrada a continuación) estás usando la API REST porque esto es lo que está detrás de ella.

Prometheus Storage: ¿Cómo optimizar el uso del disco?
Vista de destino de la Interfaz Gráfica de Prometheus

Tenemos toda la documentación sobre la API REST en la documentación oficial de Prometheus:

https://prometheus.io/docs/prometheus/latest/querying/api/

Pero, ¿qué nos proporciona esta API en términos de la base de datos de series temporales TSDB que utiliza Prometheus?

APIs de Administración de TSDB

Tenemos una API específica para gestionar el rendimiento de la base de datos TSDB, pero para poder usarla, necesitamos habilitar la API de Administración. Y eso se hace proporcionando la siguiente bandera donde estamos lanzando el servidor Prometheus --web.enable-admin-api.

Si estamos usando el Prometheus Operator Helm Chart para desplegar esto, necesitamos usar el siguiente elemento en nuestro values.yaml

## EnableAdminAPI habilita la API HTTP administrativa de Prometheus, que incluye funcionalidades como eliminar series temporales.    
## Esto está deshabilitado por defecto.
## ref: https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-admin-apis
## enableAdminAPI: true

Tenemos muchas opciones habilitadas cuando habilitamos esta API administrativa, pero hoy nos vamos a centrar en una sola operación REST que es el «stats». Este es el único método relacionado con TSDB que no requiere habilitar la API de Administración. Esta operación, como podemos leer en la documentación de Prometheus, devuelve los siguientes elementos:

headStats: Esto proporciona los siguientes datos sobre el bloque principal de la TSDB:

  • numSeries: El número de series.
  • chunkCount: El número de fragmentos.
  • minTime: La marca de tiempo mínima actual en milisegundos.
  • maxTime: La marca de tiempo máxima actual en milisegundos.

seriesCountByMetricName: Esto proporcionará una lista de nombres de métricas y su conteo de series.

labelValueCountByLabelName: Esto proporcionará una lista de nombres de etiquetas y su conteo de valores.

memoryInBytesByLabelName Esto proporcionará una lista de nombres de etiquetas y la memoria utilizada en bytes. El uso de memoria se calcula sumando la longitud de todos los valores para un nombre de etiqueta dado.

seriesCountByLabelPair Esto proporcionará una lista de pares de valores de etiquetas y su conteo de series.

Para acceder a esa API, necesitamos acceder al siguiente punto de acceso:

GET /api/v1/status/tsdb

Entonces, cuando hago eso en mi implementación de Prometheus, obtengo algo similar a esto:

{
"status":"success",
"data":{
"seriesCountByMetricName":[
{
"name":"apiserver_request_duration_seconds_bucket",
"value":34884
},
{
"name":"apiserver_request_latencies_bucket",
"value":7344
},
{
"name":"etcd_request_duration_seconds_bucket",
"value":6000
},
{
"name":"apiserver_response_sizes_bucket",
"value":3888
},
{
"name":"apiserver_request_latencies_summary",
"value":2754
},
{
"name":"etcd_request_latencies_summary",
"value":1500
},
{
"name":"apiserver_request_count",
"value":1216
},
{
"name":"apiserver_request_total",
"value":1216
},
{
"name":"container_tasks_state",
"value":1140
},
{
"name":"apiserver_request_latencies_count",
"value":918
}
],
"labelValueCountByLabelName":[
{
"name":"__name__",
"value":2374
},
{
"name":"id",
"value":210
},
{
"name":"mountpoint",
"value":208
},
{
"name":"le",
"value":195
},
{
"name":"type",
"value":185
},
{
"name":"name",
"value":181
},
{
"name":"resource",
"value":170
},
{
"name":"secret",
"value":168
},
{
"name":"image",
"value":107
},
{
"name":"container_id",
"value":97
}
],
"memoryInBytesByLabelName":[
{
"name":"__name__",
"value":97729
},
"name":"id",
"value":21450
},
{
"name":"mountpoint",
"value":18123
},
{
"name":"name",
"value":13831
},
{
"name":"image",
"value":8005
},
{
"name":"container_id",
"value":7081
},
{
"name":"image_id",
"value":6872
},
{
"name":"secret",
"value":5054
},
{
"name":"type",
"value":4613
},
{
"name":"resource",
"value":3459
}
],
"seriesCountByLabelValuePair":[
{
"name":"namespace=default",
"value":72064
},
{
"name":"service=kubernetes",
"value":70921
},
{
"name":"endpoint=https",
"value":70917
},
{
"name":"job=apiserver",
"value":70917
},
{
"name":"component=apiserver",
"value":57992
},
{
"name":"instance=192.168.185.199:443",
"value":40343
},
{
"name":"__name__=apiserver_request_duration_seconds_bucket",
"value":34884
},
{
"name":"version=v1",
"value":31152
},
{
"name":"instance=192.168.112.31:443",
"value":30574
},
{
"name":"scope=cluster",
"value":29713
}
]
}
}

También podemos verificar la misma información si usamos la nueva y experimental Interfaz de Usuario React en el siguiente punto de acceso:

/new/tsdb-status
Prometheus Storage: ¿Cómo optimizar el uso del disco?
Visualización gráfica del conteo de las 10 series principales por nombre de métrica en la nueva interfaz de usuario de Prometheus

Entonces, con eso, obtendrás las 10 series y etiquetas principales que están dentro de tu base de datos de series temporales, por lo que en caso de que algunas de ellas no sean útiles, puedes simplemente deshacerte de ellas usando los enfoques normales para eliminar una serie o una etiqueta. Esto es genial, pero ¿qué pasa si todas las que se muestran aquí son relevantes, qué podemos hacer al respecto?

Mmmm, tal vez podamos usar PromQL para monitorear esto (enfoque de dogfooding). Así que si quisiéramos extraer la misma información pero usando PromQL, podemos hacerlo con la siguiente consulta:

topk(10, count by (__name__)({__name__=~".+"}))
Prometheus Storage: ¿Cómo optimizar el uso del disco?
Top 10 de series de métricas generadas y almacenadas en la base de datos de series temporales

Y ahora tenemos todo el poder en mis manos. Por ejemplo, echemos un vistazo no a las 10 más relevantes, sino a las 100 más relevantes o cualquier otro filtro que necesitemos aplicar. Por ejemplo, veamos las métricas relacionadas con la JVM que discutimos al principio. Y lo haremos con la siguiente consulta PromQL:

topk(100, count by (__name__)({__name__=~"jvm.+"}))
Prometheus Storage: ¿Cómo optimizar el uso del disco?
Top 100 de series de métricas relacionadas con métricas de JVM

Así que podemos ver que tenemos al menos 150 series relacionadas con métricas que no estoy usando en absoluto. Pero hagámoslo aún mejor, echemos un vistazo a lo mismo pero agrupado por nombres de trabajos:

topk(10, count by (job,__name__)({__name__=~".+"}))
Prometheus Storage: ¿Cómo optimizar el uso del disco?
Resultado de verificar el conteo de las 10 series de métricas principales con el trabajo que las está generando

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.

Almacenamiento Prometheus: ¿Cómo funciona y por qué es importante?

Almacenamiento Prometheus: ¿Cómo funciona y por qué es importante?

Aprende las bases que hacen de Prometheus una gran solución para monitorear tus cargas de trabajo y úsalo para tu propio beneficio.

Prometheus es uno de los sistemas clave en las arquitecturas de nube actuales. El segundo proyecto graduado de la Cloud Native Computing Foundation (CNCF) después de Kubernetes, y es la solución de monitoreo por excelencia en la mayoría de las cargas de trabajo que se ejecutan en Kubernetes.

Si ya has usado Prometheus por algún tiempo, sabes que se basa en una base de datos de series temporales, por lo que el almacenamiento de Prometheus es uno de los elementos clave. Basado en sus propias palabras de la página oficial de Prometheus:

Cada serie temporal se identifica de manera única por su nombre de métrica y pares clave-valor opcionales llamados etiquetas, y esa serie es similar a las tablas en un modelo relacional. Y dentro de cada una de esas series, tenemos muestras que son similares a las tuplas. Y cada una de las muestras contiene un valor flotante y una marca de tiempo con precisión de milisegundos.

Enfoque predeterminado en disco

Por defecto, Prometheus utiliza un enfoque de almacenamiento local guardando todas esas muestras en disco. Estos datos se distribuyen en diferentes archivos y carpetas para agrupar diferentes fragmentos de datos.

Así que, tenemos carpetas para crear esos grupos, y por defecto, son un bloque de dos horas y pueden contener uno o más archivos dependiendo de la cantidad de datos ingeridos en ese período de tiempo, ya que cada carpeta contiene todas las muestras para esa línea de tiempo específica.

Además, cada carpeta también tiene algún tipo de archivos de metadatos que ayudan a localizar las métricas de cada uno de los archivos de datos.

Un archivo es persistente de manera completa cuando el bloque ha terminado, y antes de eso, se mantiene en memoria y utiliza una técnica de registro de escritura anticipada para recuperar los datos en caso de un fallo del servidor de Prometheus.

Así que, a un nivel alto, la estructura de directorios del directorio de datos de un servidor de Prometheus se verá algo así:

Integración de Almacenamiento Remoto

El almacenamiento predeterminado en disco es bueno y tiene algunas limitaciones en términos de escalabilidad y durabilidad, incluso considerando la mejora de rendimiento de la última versión de TSDB. Así que, si queremos explorar otras opciones para almacenar estos datos, Prometheus proporciona una manera de integrarse con ubicaciones de almacenamiento remoto.

Proporciona una API que permite escribir muestras que se están ingiriendo en una URL remota y, al mismo tiempo, poder leer datos de muestra para esa URL remota como se muestra en la imagen a continuación:

Como siempre en cualquier cosa relacionada con Prometheus, el número de adaptadores creados usando este patrón es enorme, y se puede ver en el siguiente enlace en detalle:

Resumen

Saber cómo funciona el almacenamiento de Prometheus es crítico para entender cómo podemos optimizar su uso para mejorar el rendimiento de nuestra solución de monitoreo y proporcionar un despliegue rentable.

En las siguientes publicaciones, vamos a cubrir cómo podemos optimizar el uso de esta capa de almacenamiento, asegurándonos de que solo se almacenen las métricas y muestras que son importantes para usar, y también cómo analizar cuáles métricas son las más utilizadas de la base de datos de series temporales para poder tomar buenas decisiones sobre qué métricas deben ser eliminadas y cuáles deben mantenerse.

Así que, mantente atento a la próxima publicación sobre cómo podemos tener una mejor vida con Prometheus y no morir en el intento.

📚 Want to dive deeper into Kubernetes? This article is part of our comprehensive Kubernetes Architecture Patterns guide, where you’ll find all fundamental and advanced concepts explained step by step.