Video Summary and Transcription
La charla de hoy es sobre el registro con Pino, uno de los registradores más rápidos para Node.js. La velocidad y el rendimiento de Pino se logran evitando el registro costoso y optimizando el procesamiento del bucle de eventos. Ofrece características avanzadas como el modo asíncrono y el registro distribuido. El uso de Worker Threads y Threadstream permite un procesamiento de datos eficiente. Pino.Transport permite el procesamiento de registros en un hilo de trabajo con varias opciones para destinos de registro. La charla concluye con una demostración de la salida del registro y una invitación para buscar oportunidades de trabajo.
1. Introducción a la Registro con Pino
Hoy voy a hablar sobre el registro. Trabajo para Nearform, una empresa de servicios profesionales con sede en Irlanda. Soy miembro del comité de dirección técnica y co-creador de Fastify y Pino. Pino es uno de los registradores más rápidos para Node.js con un conjunto de características mínimas. Se ha descargado 6 millones de veces al mes y estamos trabajando en la versión siete. Usar Pino es simple con una función de fábrica y ayuda a reducir la tasa de desplazamiento del registro dentro de su aplicación.
Hola a todos, soy Matteo Collina. Hoy voy a hablar sobre uno de mis temas favoritos, el registro. Solo un poco de introducción sobre mí antes de empezar. Soy Matteo Collina, en Twitter como Matteo Collina. Trabajo para una empresa llamada Nearform. Somos una empresa de servicios profesionales con sede en Irlanda. También soy miembro del comité de dirección técnica y soy el co-creador de Fastify y estas bibliotecas de las que estamos hablando hoy, Pino. También soy un arquitecto de software, por lo que normalmente ayudo a las empresas a ejecutar Node.js en producción. También escribo cada semana en mi nuevo boletín en nodeland.dev, por favor suscríbete.
De todos modos, como parte de mi, oh, esto es realmente importante. Tal vez tengo muchas descargas en NPM. Terminé manteniendo muchas cosas en el ecosistema porque como mi actividad como consultor, tiendo a equilibrar entre el trabajo del cliente y la necesidad del cliente con el mantenimiento de Node.js como ecosistema, y eso es una buena sinergia. Así que termino implementando nuevas bibliotecas y nuevos módulos para resolver problemas que tienen mis clientes, y traigo esas cosas nuevas a mis clientes. Como parte de esta iniciativa construí varias cosas como Fastify y Pino. Pino, ¿qué es Pino? Pino es uno de los registradores más rápidos para Node.js. Tiene un conjunto de características mínimas, así que hablaremos un poco sobre lo mínimo, y es una gran comunidad. Pino ahora se ha descargado 6 millones de veces al mes, y tenemos cuatro colaboradores. Tal vez tres, pero lo que sea, cuatro colaboradores. Y es la versión seis, y estamos trabajando en la versión siete. Esta charla, es sobre la versión siete. Hey, esto es realmente agradable. Así que vienen cosas nuevas.
¿Cómo usas Pino? Usar Pino es muy simple. Puedes simplemente crear tu registrador. Solo usa una función de fábrica, así que simplemente creas tu registrador, y luego empiezas a hacer info, advertencia, error, debug, esas cosas que te gustan. También tenemos esta funcionalidad de registrador hijo que te permite crear un nuevo hijo con un cierto conjunto de propiedades ya preestablecidas, y es un registrador JSON delimitado por nuevas líneas, por lo que produce JSON delimitado por nuevas líneas, por lo que es un JSON seguido de una nueva línea, y otro JSON seguido de una nueva línea. Bastante interesante. Es rápido, y puedes usar pnode para reducir drásticamente la tasa de desplazamiento del registro dentro de tu aplicación. Realmente no puedes llevarlo a cero porque todavía está haciendo IO al final, pero ayuda a reducirlo bastante. Sepa que el registro debe ser rápido.
2. La Velocidad y Rendimiento del Registro con Pino
No deberías tener un registro muy costoso porque si tienes un registro muy costoso, entonces estarás inclinado a registrar menos y no más, y necesitas más observabilidad la mayoría de las veces. Pino ha estado alrededor por un tiempo, así que, hey, días felices. Y la mayoría de lo que decimos sigue siendo moderno. La primera parte que quiero cubrir sobre Pino es cómo es tan rápido. Este diagrama explica el bucle de eventos y cómo lograr un E/S muy eficiente en Node.js y aplicaciones de Node.js con rendimiento autorizado. Cuando eso aterriza en el terreno de JavaScript, significa que, bueno, antes de hacer eso, el bucle de eventos llamó a algún C++. Así que en el lado, el código C++ dentro de Node.js, luego iniciamos la función de JavaScript, que es una función que se ejecuta, que a su vez, podría resolver una promesa o programar un siguiente tick. Y por lo tanto, también tenemos que procesar las colas de microticks. Desde el momento en que nos movemos desde el... Empezamos a llamar dentro de C++ hasta el momento en que dejamos que C++ regrese, el bucle de eventos está bloqueado. Así que no hay más eventos, nada. No está pasando nada en términos de E/S en el sistema. Uno de los... ¿Qué pasa si tienes una operación de E/S lenta? Así que imaginemos en el contexto de inicio de sesión que estás escribiendo a un destino y necesitas hacer algún manejo y procesamiento de tus registros antes de moverlos. Ahora, debido a, ya sabes, y estás escribiendo todos esos registros y tienes un lento, entonces por lo tanto tienes una operación de E/S lenta y la cantidad de tareas, tareas concurrentes aumentan. Pero si la tarea concurrente, las tareas concurrentes asíncronas aumentan, entonces también aumenta el consumo de memoria de tu aplicación.
No deberías tener un registro muy costoso porque si tienes un registro muy costoso, entonces estarás inclinado a registrar menos y no más, y necesitas más observability la mayoría de las veces.
Hay esta agradable charla llamada el Costo del Registro que mi compañero de crimen, David Marklamas, y yo hemos dado en node-conf.eu 2016. Hace mucho tiempo, ¿sabes? Pero Pino ha estado alrededor por un tiempo, así que, hey, días felices. Y puedes comprobarlo porque fue una muy buena... Es una muy buena charla. Y la mayoría de lo que decimos sigue siendo moderno. Había un montón de cosas que son diferentes y vamos a cambiar en v7 de las que vamos a hablar pronto.
Entonces, bueno, la primera parte que quiero cubrir sobre Pino es cómo es tan rápido. ¿Cómo puede ser rápido? Bueno, solo quiero darte un poco de visión general. Y gracias, James. Estas diapositivas son increíbles. Este diagrama es probablemente uno de los mejores que hemos hecho. Este diagrama explica el bucle de eventos y explica cuándo estamos haciendo E/S y cómo podemos lograr y cómo lograr un E/S muy eficiente en Node.js y aplicaciones de Node.js con rendimiento autorizado.
Entonces, en primer lugar, tienes data que llega al bucle de eventos. Así que tienes data, tienes eventos que llegan. Así que alguna E/S ha terminado o tal vez ha llegado una solicitud HTTP. Cuando eso aterriza en el terreno de JavaScript, significa que, bueno, antes de hacer eso, el bucle de eventos llamó a algún C++. Así que en el lado, el código C++ dentro de Node.js, luego iniciamos la función de JavaScript, que es una función que se ejecuta, que a su vez, podría resolver una promesa o programar un siguiente tick. Y por lo tanto, también tenemos que procesar las colas de microticks. Después de que todo eso se ha dicho y hecho, volvemos al bucle de eventos. Desde el momento en que nos movemos desde el... Empezamos a llamar dentro de C++ hasta el momento en que dejamos que C++ regrese, el bucle de eventos está bloqueado. Así que no hay más eventos, nada. No está pasando nada en términos de E/S en el sistema. Esto no es genial. Bueno, o es genial en el sentido de que es, ya sabes, si quiero hacerlo rápido, si haces mi code rápido, el tiempo que paso ejecutando JavaScript necesita ser lo más pequeño posible. Entonces... Uno de los... ¿Qué pasa en, ya sabes, si tienes una operación de E/S lenta? Así que imaginemos en el contexto de inicio de sesión que estás escribiendo a un destino y necesitas hacer algún manejo y procesamiento de tus registros antes de moverlos. Ahora, debido a, ya sabes, y estás escribiendo todos esos registros y tienes un lento, entonces por lo tanto tienes una operación de E/S lenta y la cantidad de tareas, tareas concurrentes aumenta, ¿verdad? Pero si la tarea concurrente, las tareas concurrentes asíncronas aumentan, entonces también aumenta el consumo de memoria de tu aplicación.
3. Rendimiento y Características Avanzadas de Registro con Pino
Si el consumo de memoria aumenta, se requiere más recolección de basura, que se ejecuta en la CPU. Esto puede llevar a una desaceleración en la CPU y una acumulación de eventos, lo que potencialmente puede causar un bloqueo. Para garantizar un buen rendimiento, Pino procesa los datos de forma sincrónica, evitando fugas de memoria. Pino también permite el modo asíncrono, aunque puede afectar la depuración. En 2016, Pino propuso un enfoque diferente para el registro, recomendando procesos separados o confiando en la infraestructura para el transporte de registros. Sin embargo, ahora Pino permite la distribución dentro del mismo proceso sin bloquear el hilo principal. Los usuarios han solicitado características como el formateo de registros, el envío de registros a destinos remotos, la implementación de la rotación de registros y el envío de múltiples registros a múltiples lugares simultáneamente.
Pero si el consumo de memoria aumenta, tienes que hacer más recolección de basura, que se ejecuta en la CPU. Y así, cuando la CPU se ejecuta, la recolección de basura crece, la memoria crece, la recolección de basura crece, crece en uso y luego la CPU se llena con la actividad de recolección de basura que hay que hacer. Ahora, ese es el problema, ya ves, porque la latencia y el rendimiento están profundamente conectados. Entonces, si tengo una operación lenta en mi code, entonces aumentará la concurrency, lo que aumentará la presión de la memoria, lo que ralentizará la CPU. Y es posible que debido a esa desaceleración en la CPU, la acumulación de eventos para procesar aumentará de nuevo y entrará en algún tipo de ciclo catastrófico donde hasta que la presión se alivie en algún lugar, todo estará bloqueado.
Entonces, ya sabes, el truco aquí es asegurarse de que la mayor parte del proceso se haga lo más rápido posible. Eso es todo, esa es la respuesta a esto. Y no programa más trabajo. Ahora, esto significa en el contexto del registro, por ejemplo, que si estás teniendo, si quieres enviar la misma línea de registro a múltiples destinos, será problemático porque tenemos, o especialmente incluso a través de una red, porque si intentamos hacer eso, esos data permanecerán vivos por más tiempo y en realidad estamos creando más trabajo para nuestro bucle de eventos. En Pino, hacemos todo el procesamiento de data de forma sincrónica. Así que cuando llamas a .info lo que sea, puedes estar seguro de que al usar el predeterminado, todo el procesamiento se hace dentro del macro tick. Así que no hay nada programado para ser ejecutado más tarde. Esto es fenomenal y realmente importante para obtener un buen rendimiento, porque nos aseguramos de que no queda memoria ubicada a la izquierda y se recicla esencialmente muy fácilmente. Ahora podrías activar el modo asíncrono en Pino para que el registro se borre después de un tiempo, y no se escriba inmediatamente, pero es un poco más difícil en el lado de la debugging. Hablaremos de eso en un segundo.
En la presentación original sobre Pino de 2016, teníamos esta luz sobre el hecho de que Pino es más que un módulo, es una forma de vida. Bueno, Pino, es más que un módulo. Y al principio, lo señalamos porque estaba claro que estábamos proponiendo algo radicalmente diferente. ¿Y qué estábamos proponiendo en 2016? Bueno, le decíamos a la gente, mira, necesitas implementar tu transporte como procesos separados o confiar en tu infraestructura. Así que registras en la salida estándar y tu infraestructura recoge la salida estándar y la envía a otro lugar. Sí, todavía recomendamos eso, eso no ha cambiado. Sin embargo, varios equipos se han acercado a nosotros y a nosotros también, pero realmente necesitamos ejecutar la distribución en nuestro proceso. El objetivo típico es enviar tu registro a data dog o a la búsqueda elástica o algo así. Bueno, Pino te permite hacer eso. Bueno, Pino pronto te permitirá hacer eso desde el mismo proceso sin bloquear el hilo principal. Lo veremos en un momento. Ya sabes, lo que pasó fue que todas las personas empezaron a pedirnos las mismas características. Querían formatear sus registros, querían enviarlos a un destino remoto. Querían implementar la rotación de registros, esto era una gran cosa. Y realmente querían enviar múltiples registros a múltiples lugares al mismo tiempo.
4. Uso de Worker Thread y Threadstream
Podríamos haber utilizado Worker Thread, que ahora son estables en todas las líneas de lanzamiento de soporte a largo plazo de Node.js 12 y 14. Ofrecen primitivas de sincronización fáciles como Atomics. Comencé a escribir una biblioteca llamada Threadstream, que envuelve un Worker Thread en una API basada en streams. Es rápido y permite escribir cadenas y buffers. Al proporcionar un stream escribible, puedes enviar datos al WorkerThread. Esto proporciona una forma de enviar datos a mi WorkerThread como un stream.
Al decir, bueno, deberías hacer todas esas cosas fuera del proceso. Estábamos diciendo a todos esos equipos, bueno, necesitas que tus operaciones o tu DevOps se encarguen de esas cosas. Fue más difícil para la mayoría de los equipos, para ser honesto. Entonces, y los usuarios siguen haciendo estas preguntas todos los días, todos los días, todos los días. Entonces, ¿qué podríamos hacer? Bueno, había algo que podríamos haber hecho. Podríamos haber utilizado Worker Thread. Los Worker Thread ahora son estables en todas las líneas de lanzamiento de soporte a largo plazo de Node.js 12 y 14, por supuesto. Y ofrecen algunas primitivas de sincronización fáciles, como, por ejemplo, Atomics. Y es genial. Y tal vez podríamos usarlos para construir transportes, ¿verdad? Wow, bueno, ¿cómo? Primero que nada, esta idea no es nueva. Fue originalmente mostrada por Mark Martin en una conferencia hace unos años, donde estaba usando un complemento nativo para hacer la mayor parte de este trabajo. Y mostraba un gran potencial en términos de rendimiento y performance. Así que fue bastante genial. Entonces, lo que hice fue, empecé a escribir esta biblioteca llamada Threadstream. ¿Qué hace Threadstream? Bueno, esencialmente envuelve un Worker Thread en una API basada en streams. Así que no es puramente un stream escribible porque no hereda de un escribible, pero es rápido, y puedes escribir cadenas en él. Puedes escribir buffers. Así que básicamente, llamas a streams write y simplemente empiezas a escribir en tu Thread. Y en el otro Thread, necesitas proporcionar un stream escribible. Eso es todo. Esa es la única interfaz que necesitas proporcionar. Entonces, una vez que has hecho esto, que has proporcionado ambos, es realmente genial porque ahora tengo una forma de enviar data a mi WorkerThread como un stream. Pero ya sabes, un stream es la interfaz que PNO tiene. Así que veamos cómo usar eso.
5. Uso de Pinot Transport para el procesamiento de registros
Queremos que nuestro hilo principal envíe registros a nuestro WorkerThread. Se comunican utilizando un Ring Buffer, lo que permite escribir y consumir sin bloqueo. Pinot.Transport es una nueva función que permite el procesamiento de registros en un hilo de trabajo. Ofrece varias opciones para destinos de registros e impresión bonita. Una demostración muestra el ejemplo básico de Pino y el uso de transportes para múltiples destinos.
Bueno, lo que hacemos es que queremos que nuestro hilo principal envíe registros a nuestro WorkerThread. Eso es lo que hacemos. Entonces, en una aplicación AV Node, tendremos dos hilos, uno para el principal y otro para el procesamiento de registros. ¿Cómo se comunican? Se comunican usando un Ring Buffer. Usar un Ring Buffer les permite escribir en este buffer en su mayoría sin bloquear el buffer en sí. Así que uno puede escribir y el otro puede consumir sin bloquearse entre ellos.
Entonces, siempre puedo determinar la parte a leer de ese trabajo. Así que ahora les voy a presentar Pinot Transport. He construido toda esta tensión y espero que la liberemos ahora mismo. Así que Pinot.Transport es una nueva función dentro de Pinot que te permite crear, hacer el procesamiento de registros en un transporte remoto, lo siento, en un hilo de trabajo que está envuelto como un transporte. Puedes usar modules, puedes especificar ya sea una dependencia o un solo archivo con una ruta absoluta, o puedes usar un archivo de destino o puedes usar una console e imprimir de manera bonita. Eso es todo. Así que en realidad puedes hacer muchas de esas cosas de diferentes maneras.
Así que es hora de una demostración. Así que lo que voy a hacer, voy a abrir Kibana y veremos nuestro camino. Así que es Kibana, tenemos los últimos cinco minutos, esto no es nada. Y tengo mi script. Así que primero voy a mostrarles el ejemplo y el ejemplo, este es el ejemplo básico de Pino, estos solo registran cosas y a la salida estándar. Así que lo que, lo que solíamos hacer es no ejemplo y ves que imprime esto, pero entonces podría hacer Pino Pretty y luego obtener una impresión bonita. Nota que lo que he hecho aquí es, ah, eso está bien. Así que lo que he hecho aquí es que he ejecutado en frío Node Modules Bean, punto bean barra Pino Pretty para embellecer y colorear mis bloqueos. Ahora lo que puedo hacer en su lugar es con los transportes es estos nuevos, oop yay, abrió de todos modos, yay. Y es usar esta nueva técnica donde estoy creando mi transporte Estoy especificando un archivo para un destino. Estoy especificando que voy a usar un Pino Elasticsearch para enviar los data a Elastic especificando que el nodo Elasticsearcher y haciendo una impresión bonita. Así que veamos cómo funciona. Así que he estado haciendo y oh nota que esto es el resto no cambia en absoluto. Es exactamente lo mismo. Y es bastante genial, ¿verdad? Porque puedo escribir mi transporte, no mantener mi aplicación pero hacer múltiples destinos en el mismo proceso. Bueno, ejecutemos esto. Así que si ejecuto ejemplo transportes, obtengo exactamente lo mismo...
6. Salida de Registro y Conclusión
Obtuve exactamente la misma salida que antes. Solo se agregaron estas líneas de registro porque solo muestra los registros de advertencia. Y ahora puedes ver que también tienen registros dentro de Elasticsearch. Es realmente agradable porque tenemos todos nuestros datos de una manera fácil de procesar con Kibana. Gracias por ver esta charla. Si tienes más preguntas, por favor contáctame. Estamos contratando para todo tipo de roles.
Obtuve exactamente la misma salida que antes. Solo se agregaron estas líneas de registro porque de hecho, puedo, ya sabes, esto solo muestra los registros de advertencia. Vale, aquí está. Es bastante genial. Y luego podemos ver si estos se actualizaron. Y ahora puedes ver que también tienen registros dentro de Elasticsearch. Y es realmente agradable porque puedes ver que tenemos todos nuestros data de una manera realmente fácil de procesar que Kibana nos proporciona. Así que es bastante genial.
Genial, solo quería agradecerte por ver esta charla. Si tienes más preguntas sobre Pino y Fastify y Node.js, por favor contáctame o envíame un correo electrónico. Ah, por cierto, estamos hiring para todo tipo de roles. Así que si estás interesado, sí, échale un vistazo, adiós.
Comments