El registro y el seguimiento de consultas son las mejores prácticas. Informe Yandex

Yandex.Market tiene una gran arquitectura de microservicios. La solicitud del navegador de la página principal del mercado da lugar a docenas de solicitudes integradas en diferentes servicios (backends) que son desarrolladas por diferentes personas. En dicho sistema, puede ser difícil de entender por qué razón la solicitud cayó o tardó mucho tiempo en procesarse.


Anatoly Ostrovsky megatolyaexplica cómo su equipo resolvió este problema y comparte prácticas específicas del mercado, pero generalmente relevantes para cualquier gran servicio. Su informe se basa en su propia experiencia de desplegar un nuevo mercado en un tiempo bastante corto. Durante varios años, Tolya dirigió el equipo de desarrollo de interfaz en el mercado, y ahora se ha movido hacia la dirección de vehículos no tripulados.

- Todos nuestros mercados están construidos de acuerdo con principios generales. Este es un gran sistema único. Pero si hablamos de la interfaz, desde el punto de vista del usuario, las aplicaciones son completamente diferentes.



Al mismo tiempo, nuestras interfaces van a muchos backends. Algunas veces estos backends son similares entre sí (diferentes instancias de la misma aplicación). Y a veces son exclusivos del servicio (facturación especial). La estructura de dicho sistema puede considerarse una arquitectura clásica de microservicio.

Siempre hay un problema en un servicio grande: es difícil entender qué está sucediendo exactamente en él. O, por ejemplo, lo que sucede en el momento en que se produce un error de pago con el usuario. Supongamos que sucedió en su casa ayer, y hoy necesitamos entender lo que sucedió.



El backend 2 puede "grabarse" para un producto específico, en un momento específico o para usuarios específicos. Necesitamos poder responder a cualquier situación.



Tenemos muchos backends y, como dije, pueden caminar solos. Si esto se presenta en forma de gráfico, resultará bastante confuso. En la vida real, puede haber cientos de microservicios. Imagine cuántas conexiones habrá entre ellos.

Hay muchos pasos para profundizar en este tema. Hablaré brevemente de cada uno de ellos.



En primer lugar, acuerde con sus colegas del backend un sistema común de marcado de solicitudes: es más fácil encontrarlos más tarde. A continuación, debe poder reproducir rápidamente el problema. Suponga que se produjo un error de pago: intente comprender rápidamente cómo sucedió y en qué backend. Almacene registros no solo en archivos, sino también en la base de datos para que se puedan realizar agregaciones. Y, por supuesto, una parte importante del proceso son los gráficos y el monitoreo. A continuación, en orden.

Sistema de identificación de solicitud unificada




Esta es una de las herramientas más fáciles de entender lo que está sucediendo con el servicio. Acuerde con sus colegas que, por ejemplo, su interfaz genera algún tipo de solicitud de identificación (la variable requestId en la imagen) y luego la arroja a todos los endpoints de los backends. Y el backend en sí mismo no reinventa nada. Toma el ID de solicitud que ha llegado y lo reenvía más lejos en solicitudes a sus servidores. Al mismo tiempo, puede especificar su prefijo, de modo que entre el requestId idéntico sería posible encontrar este backend en particular.



Por lo tanto, cuando engulle sus registros, entonces, asegurándose de que sus registros digan, por ejemplo, que el back-end es quinientos, puede haber dos opciones. O bien, le dará esta identificación de solicitud a sus colegas y ellos la verán en sus registros, o lo verá usted mismo.



Todos nuestros registros están marcados con dicha identificación para no solo comprender qué sucedió y en qué momento, sino también para mantener el contexto de esta solicitud. Es asíncrono, luego puede agregar algo al registro. Y si muerdes a requestId, nada bueno saldrá de eso.

rizo


Para reproducir el problema, utilizamos la utilidad cURL. Esta es una utilidad de consola que realiza solicitudes de red: http y https. cURL admite muchos más protocolos diferentes, pero cuando se realiza desarrollo web, es más fácil suponer que esta es una herramienta para trabajar con solicitudes http (s).



Para familiarizarse con el equipo de cURL, puede ir a cualquier sitio, luego ir a Red y copiar cualquier solicitud en forma de cURL. El resultado es una línea tan grande:



si intenta resolverlo, entonces no hay nada de qué preocuparse. Intentemos desarmarlo.



Aquí hay una solicitud para market.yandex.ru.



Aquí se ha agregado un User-Agent, que ya ocupa mucho espacio.



De hecho, el resto son cookies. Hay bastantes de ellos en el código Yandex. En forma serializada, tienen un aspecto muy formidable. De hecho, no hay nada más aparte de ellos.

Entonces, ¿para qué sirve cURL? Si lo copió y lo ejecutó, entonces vio la misma página market.yandex.ru que yo, solo la computadora en la que se ejecutaba sería diferente. Por supuesto, algunos efectos secundarios podrían dar diferencias en las direcciones IP, pero en general serían las mismas solicitudes. Reproduciríamos el mismo escenario.



Para no inventar tales consultas cURL cada vez, puede usar el formato npm-package format-curl.



Toma todos los parámetros de solicitud que la función generalmente toma, es decir, en este caso solo encabezados y url. Pero también sabe cómo consultar, el cuerpo, etc. Y la salida es solo una cadena con una solicitud cURL.



Por lo tanto, todos nuestros registros en el entorno de desarrollo también contienen solicitudes de cURL.



Incluso registramos solicitudes de cURL de back-end directamente en el navegador para ver de inmediato cómo vamos a nuestros backends sin mirar la consola del navegador.



Tenga en cuenta que las solicitudes de cURL implican la transferencia de cookies de sesión; esto es malo. Si rechazó su solicitud de cURL en market.yandex.ru, entonces podría ingresar a su Market y a cualquier otro servicio Yandex bajo su inicio de sesión. Por lo tanto, no almacenamos tales solicitudes en ningún lugar, y las registramos solo en bancos de pruebas para nosotros mismos; dichos datos no se pueden filtrar.

Clickhouse


A continuación hablaré sobre registros estructurados. Aquí tendré en cuenta la base de datos específica de ClickHouse, pero puede elegir cualquiera. ClickHouse es un DBMS columnar, es más conveniente seleccionar entre una gran cantidad de datos y tomar grandes cantidades de datos. Es bueno que pueda guardar una gran parte del registro en él y luego, por ejemplo, hacer algún tipo de agregación de mil millones de registros.



En este caso, el ejemplo de selección de ClickHouse es SQL simple. Aquí mostramos el número de solicitudes de códigos de estado para hoy.



Como resultado, tendremos 180 mil doscientos setecientos quinientos, y los códigos de estado restantes, por ejemplo, no nos interesan. Pero, ¿cómo podemos usar esto de manera interesante?



Podemos decir que la proporción de doscientos a la proporción del número total de respuestas es el Indicador de nivel de servicio, que responde a la pregunta de qué tan bien funciona nuestra aplicación en términos de códigos de estado. Aunque simple, ya está hablando de algo.



Según nuestro indicador, podemos llegar al primer SLI, es decir, por ejemplo, que el 99% de nuestras solicitudes deberían estar bien. Y aquí podemos comparar que realizamos nuestro SLI. Si no se hubieran cumplido, podríamos haber intentado distinguir algunas de las últimas solicitudes que habrían sido quinientas, o simplemente cosas críticas.



Por ejemplo, los errores de pago son críticos para nosotros, pero en este caso devolverán cero, es una suerte :)



¿Cómo puede hacer sus registros de una forma tan conveniente y que puedan tomarse a través de SQL?



Este es un tema para otro gran informe, y todo depende de su infraestructura. Pero parece que hay dos formas. Primero: envíe los metadatos directamente al tiempo de ejecución, directamente a la base de datos. Lo hacemos de manera diferente, de la segunda manera: seguimos el archivo de registro y enviamos fragmentos en la base de datos o en un lugar intermedio.

Esto funciona para nosotros en lugar de varias capas: enviamos registros de una instancia específica a un servidor de almacenamiento remoto de dichos registros.

Solicitar seguimiento


No existe el concepto de "rastreo de consultas". Este término fue acuñado por Google.



Si busca en Internet "seguimiento de consultas", verá el comando traceroute. Quizás esto es similar al rastreo de consultas.



Incluso hay un programa de consola, y aquí lo ejecuté para el sitio web bringly.ru (un servicio que desarrollamos la primavera pasada). Ayuda a comprender a través de qué máquinas y servidores pasa la solicitud antes de que llegue al equilibrador, que responderá por diseño o por otra cosa.



Aquí está nuestro equilibrador. Por rastreo de consultas, no queremos decir esto, sino todo lo que sucede dentro de nuestro equilibrador: cómo la solicitud vive más dentro de nuestra aplicación node.js.



Vemos esto en forma de una línea de tiempo, donde se muestra el tiempo horizontal y la secuencia vertical de solicitudes. En este caso, tenemos una solicitud para la tarjeta del producto, donde se puede ver que se trata de una solicitud al back-end de nuestra autorización. Después de su decisión, fueron tres largas filas: esta es una solicitud a nuestro backend principal para una canasta, tarjeta de producto y productos similares. Entonces tenemos un rastro.



Aquí puede ver la misma solicitud de autorización, y luego se fue el backend. En este caso, el backend no se comporta de manera óptima, ya que tiene muchas consultas consecutivas en su base de datos. Probablemente, tal consulta podría optimizarse.



Y aquí hay un ejemplo de un rastro, cuando no fuimos a ningún backend, sino que inmediatamente dimos el estado de 500. ¿Cómo nos resulta útil ese rastro? No tenemos que molestar a los colegas. Tenemos la identificación de esta solicitud, por lo que podemos mirar en los registros nosotros mismos y descubrir qué está sucediendo.



Aquí está la situación opuesta. Backend dijo que algo andaba mal y, al mismo tiempo, escribió en la metainformación qué sucedió exactamente: apareció algún tipo de seguimiento de la pila.



¿Cómo hacerse la misma herramienta?

Lo más importante aquí es la base de datos. Si tiene el "INSERT INTO" más simple en la base de datos de algunas acciones con el servicio, más tarde puede usar al menos SQL para encontrar los eventos necesarios. Y si es necesario, puede hacer una interfaz para esto.

Gráficos


Este es un tema muy interesante, no me detendré en detalles hoy, por supuesto, :)



Hablemos sobre el registro. Tenemos muchos gráficos, los miramos cuando lanzamos algo, y en los tiempos hay mucho ruido.



Los gráficos ayudan a ver visualmente que algo está mal. Y luego aún debe mirar los registros y comprender qué hay de malo en ellos. En este caso, el aumento inmediato después de la liberación al menos significa que dicha liberación debe revertirse inmediatamente.

Supervisión


Una parte aún más importante y un mayor grado de inmersión en este tema es el monitoreo. Por monitoreo, entiendo, en primer lugar, el monitoreo automático de gráficos y, en segundo lugar, cualquier regla automatizada para monitorear algo.



Monitoreamos la proporción de quinientos al número total de respuestas por minuto. También monitoreamos cuatrocientos, la presencia de una carga en el servicio, verificando la perilla de verificación de estado, que tira de la perilla de ping de cada uno de los backends, etc.



Además, tenemos paneles de monitoreo que incluimos en pantallas cerca de estaciones de trabajo. Entonces, inmediatamente vemos cuál de los "sonrojos" de monitoreo. Por ejemplo, aquí es uno de los principales, donde la interfaz y nuestro servidor principal son visibles. Aquí puede ver que algunos controles se iluminan en el backend. Esto significa que en ese momento la persona responsable de este servicio recibirá un mensaje en Telegram, o tal vez incluso lo llamarán, depende de la configuración de monitoreo.

Resumen


Un único requestId lo ayudará a encontrar problemas más fácilmente en un servicio que consta de varias aplicaciones. El cURL correcto le permitirá reproducir con mayor precisión los problemas y ver cómo usted mismo, por ejemplo, envía datos al backend. Los registros estructurados le permitirán obtener SLI, y son más convenientes de usar que los registros de texto normales. Y no te olvides de seguir los cuadros y realizar el seguimiento.

Recomiendo leer el libro de Ingeniería de confiabilidad del sitio de Google si está interesado en cosas de infraestructura.

All Articles