Durante una reunión reciente del equipo fuera del sitio, uno de los temas en los que trabajó el equipo de ingeniería fue mejorar el rendimiento de Filebeat . La idea era generar y revisar perfiles pprof e identificar áreas de mejora en nuestro código base. En particular, se analizo los perfiles de memoria durante escenarios de casos de uso de registro específicos.
Al igual que con el trabajo de investigación de todo detective, sabíamos que debíamos investigar la ruta activa del evento para encontrar mejoras. Así que comenzamos mirando lugares que inmediatamente parecían parte del camino activo y luego investigamos más a fondo mirando el código.
Investigación
Comenzamos definiendo y ejecutando nuestro caso de prueba y recopilando perfiles de memoria. En un nivel alto, la configuración de prueba consistió en una instancia de Filebeat que enviaba datos a un clúster ES remoto en la nube. No hemos configurado ningún tipo de procesador, solo una única entrada que lee un archivo de registro de 2 millones de líneas.
Nos centramos en el montón asignado ( alloc_space ), que mostraría la asignación de memoria acumulada para nuestro punto de referencia. Al centrarnos en lo anterior y reducir la asignación, ayudaríamos a nuestro GC al reducir la carga en las etapas del GC. Hay una interesante charla de Thomas Dullien que analiza aventuras similares en el camino hacia el análisis del rendimiento y el impacto de GC.
Abrir el perfil fue tan simple como ejecutar el siguiente comando.
go tool pprof -http=:8080 -alloc_objects heap-profile.pprof
La siguiente es una vista parcial:
Al observar la ruta verde de arriba, notamos que desde readFromSource bajamos a readjson.Next , como se esperaba, ya que estamos leyendo desde una fuente de archivo NDJSON. Curiosamente, a partir de ahí, vemos una llamada de función a jsontransform.WriteJSONKeys que en realidad está asignando la memoria necesaria. Esto inmediatamente parece sospechoso porque al observar el diagrama debajo de esa función, vemos que la mayor parte de la asignación de memoria ocurre en logp.newLogger.
Al observar el código fuente de esa función , vemos que creamos una instancia de un nuevo registrador por invocación de función. Dado que esa función se llama para cada línea, terminamos asignando un nuevo registrador para cada evento de registro que se ha leído del archivo.
Para comprender el consumo de memoria de esta lógica, volvemos a mirar el gráfico para ver que en general la función consumió 21 GB de memoria, como se resalta en el círculo rojo. En nuestro punto de referencia específico, el registrador por sí solo consumió 9,2 GB, lo que está muy cerca del 50 % del uso de memoria (!!).
Como parece un buen candidato para mejorar, inmediatamente generamos una solicitud de extracción . Después de discutirlo con el equipo, resultó que no necesitábamos el registrador ya que el error se estableció en el evento.
Después de eliminar el registrador y volver a probarlo, obtuvimos una vista diferente:
go tool pprof -http=:8080 -alloc_objects heap-profile.pprof
La búsqueda de mejoras continúa
Este ejemplo fue solo una de las mejoras que el equipo de Platform Ingest de Elastic encontró durante esa reunión externa. Continuaremos con más publicaciones sobre mejoras de rendimiento en las próximas semanas.
Obtenga más información sobre las posibilidades con Filebeat .