Prometheus: una combinación de lectura remota y traducción en streaming
Se ha lanzado una nueva versión 2.13.0 de Prometheus, que contiene muchas correcciones de errores y mejoras. Puedes ver estos cambios aquí. Esta es una característica que muchos usuarios o proyectos estaban esperando: una versión de transmisión fragmentada de la API de lectura remota.
En este artículo, profundizaré en los cambios que realizamos en el protocolo remoto, por qué los cambiamos y cómo usarlo de manera efectiva.
Desde la versión 1.x, Prometheus ha podido interactuar con el almacenamiento remoto a través de la API remota.
La API permite que los sistemas de terceros interactúen con datos de métricas de dos maneras:
Esta es la forma más común de colocar datos de Prometheus en el almacenamiento del sistema de terceros. En este modo, Prometheus envía periódicamente un lote de datos de muestra a un punto final determinado.
En marzo, la escritura remota basada en WAL recibió una gran mejora en confiabilidad y uso de recursos. Vale la pena señalar que todo el almacenamiento de terceros admite este método.
El método de lectura es menos común. Se agregó en marzo de 2017
(inclusión interna del lado del servidor) y no ha habido ningún desarrollo importante desde entonces.
La versión 2.13.0 de Prometheus corrige un cuello de botella de recursos conocido en la API de lectura. Este artículo destacará estas mejoras.
El punto clave de la lectura remota es consultar directamente el almacenamiento de Prometheus (TSDB) sin realizar cálculos PromQL. Es similar a la interfaz Querier que obtiene datos de la capa de almacenamiento.
Esta función permite el acceso a los datos de cronometraje recopilados por Prometheus. Los principales escenarios de uso de la lectura remota son los siguientes:
La API de lectura remota expone un punto final HTTP simple, que espera que el formato de datos sea el siguiente:
A través de este protocolo, el El cliente puede El intervalo de tiempo y los intervalos de tiempo de inicio y finalización del comparador acceden a los datos en el almacenamiento de Prometheus para obtener datos de tiempo específicos
El formato de los datos devueltos es el siguiente:
Devoluciones de lectura remota datos de sincronización coincidentes, que contienen datos sin procesar (incluidos el valor y la marca de tiempo)
Hay dos problemas clave con la lectura remota. Es fácil de usar y comprender, pero no tiene capacidades de transmisión en una sola solicitud HTTP en el formato protobuf que definimos. En segundo lugar, la respuesta son datos en formato sin formato (valor float64 y marca de tiempo int64), no los datos comprimidos con codificación basada en "Chunk" almacenados por TSDB.
La lógica del lado del servidor para la lectura remota sin utilizar transmisiones es:
Aquí está el uso de memoria durante una solicitud de lectura remota para Prometheus y Thanos Sidecar (cliente de lectura remota): p>
Vale la pena señalar que incluso para el método query_range de la interfaz HTTP nativa de Prometheus, consultar series 10,000 no es una buena idea, porque su navegador no quiere buscar, almacenar y representar cientos de megabytes de datos. Además, tener tantos datos no es práctico para paneles y representaciones porque es imposible que los humanos lean tantos datos. Es por eso que generalmente no emitimos consultas con más de 20 marcas de tiempo.
Si bien no hay ningún problema con esto, otro enfoque técnico tradicional es obtener las 20 series temporales agregadas a través de una consulta de agregación, pero el motor de consulta subyacente tiene que calcular la respuesta a través de miles de series (por ejemplo, usando agregadores). Esta es la razón por la que sistemas como Thanos utilizan datos TSDB leídos desde ubicaciones remotas, entre otros datos, que a menudo se solicitan en grandes cantidades.
Es útil comprender cómo Prometheus itera los datos al realizar consultas. El concepto central se puede ver en el tipo llamado SeriesSet devuelto por el método Select del Querier. Las interfaces son las siguientes:
La serie de interfaces anterior proporciona funciones basadas en "flujo" para el proceso. Ya no necesitamos calcular previamente una lista de secuencias que contenga muestras. Usando esta interfaz, cada implementación de SeriesSet.Next() puede obtener una serie según sea necesario. También podemos obtener dinámicamente cada muestra individualmente a través de SeriesIterator.Next.
A través de este protocolo, Prometheus puede asignar la menor cantidad de memoria posible porque el motor PromQL puede recorrer las muestras de una manera más optimizada para calcular los resultados de la consulta.
Esto es muy importante para la API de lectura remota porque podemos enviar repetidamente datos parciales al cliente en fragmentos desde una única secuencia cronometrada a través del mismo formulario de llamada. Dado que protobuf en sí no tiene un mecanismo para dividir los datos de los mensajes, ampliamos la definición de proto para permitir el envío de un conjunto de mensajes de búfer de protocolo pequeños en lugar de un cuerpo de mensaje enorme. A este modo de lectura remota lo llamamos STREAMED_XOR_CHUNKS y al modo anterior SAMPLES. El protocolo extendido significa que Prometheus ya no necesita almacenar en búfer toda la respuesta y puede enviar una trama individual ordenada al llamar a SeriesSet.Next o SeriesIterator.Next para iterar y reutilizar los siguientes datos de tiempo en la misma página de memoria tanto como sea posible.
La respuesta al modo STREAMED_XOR_CHUNKS ahora es el siguiente conjunto de mensajes (marcos) de Protobuf.
Puedes notar que los marcos de mensajes ya no contienen los datos del formato original. Esta es la segunda mejora que hicimos: enviamos el mensaje de ejemplo en fragmentos (mire el video para obtener más información sobre los fragmentos), que son exactamente los mismos fragmentos que almacenamos en TSDB.
Terminamos usando la siguiente lógica del lado del servidor:
Todos nuestros diseños están aquí
Rendimiento de este nuevo enfoque en comparación con la solución anterior, ¿cómo?
Comparemos las capacidades de lectura remota de Prometheus 2.12.0 y 2.13.0. Al igual que con los resultados preliminares proporcionados al principio de este artículo, utilicé Prometheus como servidor y Thanos sidecar como cliente de lectura remota. Toda la prueba se realizó en un entorno k8s en la ventana acoplable de mi computadora portátil (Lenovo X1 16GB, i7 8th). (usando kind )
Los datos se generan manualmente y representan 10.000 secuencias altamente dinámicas (en el peor de los casos).
Los resultados detallados de las pruebas se pueden ver en el repositorio de Thanosbench.
La reducción de memoria es el objetivo principal de nuestra solución. A lo largo de la solicitud, el búfer de Prometheus era de aproximadamente 50 MB, mientras que Thanos solo usó una pequeña cantidad de memoria. Gracias a la transmisión de Thanos gRPC StoreAPI, el sidecar ahora es un proxy muy simple.
Además, probé diferentes plazos y números de secuencias, pero como era de esperar, siempre vi asignaciones de hasta 50 MB para Prometheus y cero para Thanos. Esto demuestra que nuestras lecturas remotas siempre utilizan un tamaño de memoria constante sin importar cuántas muestras solicite individualmente. La cantidad de memoria asignada se ve mucho menos afectada por la cantidad de datos solicitados y siempre asigna la misma cantidad de memoria sin importar la cantidad de datos que solicite.
La planificación de la capacidad para el tráfico de usuarios se vuelve más fácil con la ayuda de límites de concurrencia.
La utilización de la CPU también mejoró durante mis pruebas, duplicándose.
Con transmisiones y menos codificación, también reducimos la latencia de respuesta para solicitudes de lectura remota.
Lectura remota durante un lapso de 8 horas que contiene 10.000 secuencias:
Lapso de tiempo de 2 horas:
Procesamiento lateral y secuencias para Prometheus y Thanos En términos de latencia, además de una reducción de 2,5 veces en la latencia de respuesta, la versión de transmisión responde rápidamente, mientras que la versión sin transmisión tiene una latencia del cliente de 27 segundos (tiempo real menos tiempo del usuario).
La lectura remota se amplía de forma compatible con versiones anteriores y posteriores. Esto se debe a que protobuf y Accept_response_types son campos ignorados por las versiones anteriores, y funcionará bien si la versión anterior del cliente (suponiendo lectura remota en modo SAMPLES) no admite Accept_response_types.
Compatibilidad hacia atrás y hacia adelante del protocolo de lectura remota:
Para utilizar el nuevo Prometheus v2.13.0 basado en lectura remota en streaming, el sistema de terceros debe estar en la solicitud. Se agregaron tipos_de_respuesta aceptados = [STREAMED_XOR_CHUNKS]. CHUNKS] se agrega a la solicitud.
Prometheus luego reemplazará el cuerpo del mensaje anterior con ChunkedReadResponse. Cada mensaje ChunkedReadResponse se ajusta a una suma de comprobación CRC32 Castagnoli de tamaño varint y tamaño fijo bigendian uint32.
Para Go Voice, recomendamos usar ChunkedReader para leer la transmisión directamente
Tenga en cuenta que bajo la condición STREAMED_XOR_CHUNKS.storage.remote.read-concurrent-limit, Storage.remote.read - La configuración del límite de muestra ya no tendrá ningún efecto.
También se proporciona un nuevo elemento de configuración Storage.remote.read-max-bytes-in-frame para controlar el tamaño máximo de cada cuerpo de mensaje. El valor predeterminado recomendado es 1 MB, ya que Google recomienda que los mensajes protobuf no superen el tamaño de 1 MB.
Como se mencionó anteriormente, Thanos se beneficia enormemente de esta característica y agregó capacidades de lectura remota de transmisión en v0.7.0, por lo que en Prometheus 2.13.0 o posterior, tomará automáticamente la forma de una lectura remota de transmisión.
La versión 2.13.0 introdujo la lectura remota extendida y la implementación del lado del servidor de Prometheus. Sin embargo, para utilizar completamente el protocolo de lectura remota extendida, aún es necesario completar algo de trabajo:
. En resumen En otras palabras, las principales ventajas de la lectura remota de transmisión fragmentada son:
Si tiene alguna pregunta o comentario, no dude en enviar un problema en GitHub o preguntar en la lista de correo.