Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Hola, mi nombre es Evgeniy. Trabajo en la infraestructura de búsqueda de Yandex.Market. Quiero contarle a la comunidad Habr sobre la cocina interior del Mercado y tengo mucho que contar. En primer lugar, cómo funciona, procesos y arquitectura la búsqueda de Mercado. ¿Cómo afrontamos situaciones de emergencia? ¿Qué sucede si un servidor deja de funcionar? ¿Qué pasa si hay 100 servidores de este tipo?

También aprenderá cómo implementamos nuevas funciones en varios servidores a la vez. Y cómo probamos servicios complejos directamente en producción, sin causar ningún inconveniente a los usuarios. En general, cómo funciona la búsqueda de Mercado para que todos lo pasen bien.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Un poco sobre nosotros: qué problema solucionamos

Cuando ingresa texto, busca un producto por parámetros o compara precios en diferentes tiendas, todas las solicitudes se envían al servicio de búsqueda. La búsqueda es el servicio más grande del mercado.

Procesamos todas las solicitudes de búsqueda: de los sitios market.yandex.ru, beru.ru, el servicio Supercheck, Yandex.Advisor, aplicaciones móviles. También incluimos ofertas de productos en los resultados de búsqueda en yandex.ru.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Por servicio de búsqueda entiendo no sólo la búsqueda en sí, sino también una base de datos con todas las ofertas del Mercado. La escala es la siguiente: se procesan más de mil millones de solicitudes de búsqueda por día. Y todo debería funcionar rápidamente, sin interrupciones y producir siempre el resultado deseado.

Qué es qué: arquitectura de mercado

Describiré brevemente la arquitectura actual del Mercado. Se puede describir aproximadamente mediante el siguiente diagrama:
Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla
Digamos que nos llega una tienda asociada. Dice que quiero vender un juguete: este gato malvado con un chirriador. Y otro gato enojado sin chirriador. Y solo un gato. Luego la tienda necesita preparar ofertas que el Mercado busca. La tienda genera un xml especial con ofertas y comunica la ruta a este xml a través de la interfaz de afiliado. Luego, el indexador descarga periódicamente este xml, busca errores y guarda toda la información en una enorme base de datos.

Hay muchos xml guardados de este tipo. A partir de esta base de datos se crea un índice de búsqueda. El índice se almacena en formato interno. Después de crear el índice, el servicio de diseño lo carga en los servidores de búsqueda.

Como resultado, aparece un gato enojado con un chirriador en la base de datos y el índice del gato aparece en el servidor.

Te contaré cómo buscamos un gato en la parte sobre arquitectura de búsqueda.

Arquitectura de búsqueda de mercado

Vivimos en un mundo de microservicios: cada solicitud entrante market.yandex.ru genera muchas subconsultas y docenas de servicios participan en su procesamiento. El diagrama muestra sólo algunos:

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla
Esquema de procesamiento de solicitudes simplificado

Cada servicio tiene algo maravilloso: su propio equilibrador con un nombre único:

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

El equilibrador nos brinda mayor flexibilidad en la gestión del servicio: puede, por ejemplo, apagar los servidores, lo que a menudo es necesario para las actualizaciones. El equilibrador ve que el servidor no está disponible y redirige automáticamente las solicitudes a otros servidores o centros de datos. Al agregar o eliminar un servidor, la carga se redistribuye automáticamente entre los servidores.

El nombre único del equilibrador no depende del centro de datos. Cuando el servicio A realiza una solicitud a B, de forma predeterminada, el equilibrador B redirige la solicitud al centro de datos actual. Si el servicio no está disponible o no existe en el centro de datos actual, la solicitud se redirige a otros centros de datos.

Un único FQDN para todos los centros de datos permite que el servicio A se abstraiga completamente de las ubicaciones. Su solicitud al servicio B siempre será procesada. La excepción es el caso cuando el servicio está ubicado en todos los centros de datos.

Pero no todo es tan color de rosa con este equilibrador: tenemos un componente intermedio adicional. El equilibrador puede ser inestable y este problema se resuelve con servidores redundantes. También hay un retraso adicional entre los servicios A y B. Pero en la práctica es inferior a 1 ms y para la mayoría de los servicios esto no es crítico.

Cómo afrontar lo inesperado: equilibrio y resiliencia del servicio de búsqueda

Imagina que hay un colapso: necesitas encontrar un gato con un chirriador, pero el servidor falla. O 100 servidores. ¿Cómo salir? ¿De verdad vamos a dejar al usuario sin gato?

La situación es aterradora, pero estamos preparados para ello. Te lo diré en orden.

La infraestructura de búsqueda está ubicada en varios centros de datos:

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Al diseñar, incluimos la posibilidad de cerrar un centro de datos. La vida está llena de sorpresas: por ejemplo, una excavadora puede cortar un cable subterráneo (sí, eso sucedió). La capacidad de los centros de datos restantes debería ser suficiente para soportar los picos de carga.

Consideremos un único centro de datos. Cada centro de datos tiene el mismo esquema de operación del balanceador:

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla
Un equilibrador consta de al menos tres servidores físicos. Esta redundancia está hecha para brindar confiabilidad. Los equilibradores funcionan con HAProx.

Elegimos HAProx por su alto rendimiento, bajos requisitos de recursos y amplia funcionalidad. Nuestro software de búsqueda se ejecuta dentro de cada servidor.

La probabilidad de que falle un servidor es baja. Pero si tiene muchos servidores, aumenta la probabilidad de que al menos uno caiga.

Esto es lo que sucede en la realidad: los servidores fallan. Por lo tanto, es necesario monitorear constantemente el estado de todos los servidores. Si el servidor deja de responder, se desconecta automáticamente del tráfico. Para ello, HAProxy tiene un control de estado incorporado. Va a todos los servidores una vez por segundo con una solicitud HTTP "/ping".

Otra característica de HAProxy: la verificación del agente le permite cargar todos los servidores de manera uniforme. Para hacer esto, HAProxy se conecta a todos los servidores y estos devuelven su peso dependiendo de la carga actual de 1 a 100. El peso se calcula en función de la cantidad de solicitudes en la cola para procesamiento y la carga en el procesador.

Ahora sobre encontrar el gato. La búsqueda da como resultado solicitudes como: /search?text=gato+enojado. Para que la búsqueda sea rápida, todo el índice cat debe caber en la RAM. Incluso la lectura desde el SSD no es lo suficientemente rápida.

Érase una vez, la base de datos de ofertas era pequeña y la RAM de un servidor era suficiente para ello. A medida que la base de oferta creció, todo ya no cabía en esta RAM y los datos se dividieron en dos partes: fragmento 1 y fragmento 2.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla
Pero esto siempre sucede: cualquier solución, incluso una buena, genera otros problemas.

El equilibrador todavía fue a cualquier servidor. Pero en la máquina donde llegó la solicitud, solo había la mitad del índice. El resto estaba en otros servidores. Por lo tanto, el servidor tuvo que ir a alguna máquina vecina. Después de recibir datos de ambos servidores, los resultados se combinaron y reclasificaron.

Dado que el equilibrador distribuye las solicitudes de manera uniforme, todos los servidores se dedicaban a reclasificar y no solo a enviar datos.

El problema se producía si un servidor vecino no estaba disponible. La solución fue especificar varios servidores con diferentes prioridades como servidor "vecino". Primero, la solicitud se envió a los servidores del rack actual. Si no hubo respuesta, la solicitud se envió a todos los servidores de este centro de datos. Y por último, la solicitud llegó a otros centros de datos.
A medida que crecía el número de propuestas, los datos se dividieron en cuatro partes. Pero este no fue el límite.

Actualmente, se utiliza una configuración de ocho fragmentos. Además, para ahorrar aún más memoria, el índice se dividió en una parte de búsqueda (que se utiliza para la búsqueda) y una parte de fragmento (que no participa en la búsqueda).

Un servidor contiene información para un solo fragmento. Por lo tanto, para buscar en el índice completo, debe buscar en ocho servidores que contengan diferentes fragmentos.

Los servidores están agrupados en clústeres. Cada grupo contiene ocho motores de búsqueda y un servidor de fragmentos.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla
El servidor de fragmentos ejecuta una base de datos de valores clave con datos estáticos. Son necesarios para emitir documentos, por ejemplo, una descripción de un gato con un chirriador. Los datos se transfieren especialmente a un servidor independiente para no cargar la memoria de los servidores de búsqueda.

Dado que los ID de los documentos son únicos solo dentro de un índice, podría surgir una situación en la que no haya documentos en los fragmentos. Bueno, o que para una identificación habrá contenido diferente. Por lo tanto, para que la búsqueda funcionara y se obtuvieran resultados, era necesaria la coherencia en todo el clúster. A continuación le diré cómo monitoreamos la coherencia.

La búsqueda en sí está estructurada de la siguiente manera: una solicitud de búsqueda puede llegar a cualquiera de los ocho servidores. Digamos que llegó al servidor 1. Este servidor procesa todos los argumentos y comprende qué y cómo buscar. Dependiendo de la solicitud entrante, el servidor puede realizar solicitudes adicionales a servicios externos para obtener la información necesaria. Una solicitud puede ir seguida de hasta diez solicitudes a servicios externos.

Después de recopilar la información necesaria, se inicia una búsqueda en la base de datos de ofertas. Para ello, se realizan subconsultas a los ocho servidores del clúster.

Una vez recibidas las respuestas, se combinan los resultados. Al final, es posible que se necesiten varias subconsultas más al servidor de fragmentos para generar los resultados.

Las consultas de búsqueda dentro del clúster tienen este aspecto: /shard1?text=gato+enojado. Además, constantemente se realizan subconsultas del formulario una vez por segundo entre todos los servidores dentro del clúster: /estado.

Solicitud /estado detecta una situación en la que el servidor no está disponible.

También controla que la versión del motor de búsqueda y la versión del índice sean las mismas en todos los servidores; de lo contrario, habrá datos inconsistentes dentro del clúster.

A pesar de que un servidor de fragmentos procesa solicitudes de ocho motores de búsqueda, su procesador tiene una carga muy ligera. Por lo tanto, ahora transferiremos los datos del fragmento a un servicio independiente.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Para transferir datos, introdujimos claves universales para documentos. Ahora es imposible que se produzca una situación en la que el contenido de otro documento se devuelva utilizando una clave.

Pero la transición a otra arquitectura aún no está completa. Ahora queremos deshacernos del servidor de fragmentos dedicado. Y luego alejarse por completo de la estructura del grupo. Esto nos permitirá seguir escalando fácilmente. Una ventaja adicional son los importantes ahorros de hierro.

Y ahora a las historias de miedo con final feliz. Consideremos varios casos de indisponibilidad del servidor.

Sucedió algo terrible: un servidor no está disponible

Digamos que un servidor no está disponible. Luego, los servidores restantes en el clúster pueden continuar respondiendo, pero los resultados de la búsqueda estarán incompletos.

A través de verificación de estado /estado Los servidores vecinos entienden que uno no está disponible. Por lo tanto, para mantener la integridad, todos los servidores del clúster por solicitud /silbido comienzan a responder al equilibrador que tampoco están disponibles. Resulta que todos los servidores del clúster murieron (lo cual no es cierto). Éste es el principal inconveniente de nuestro esquema de clusters y por eso queremos alejarnos de él.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

El equilibrador reenvía las solicitudes que fallan con un error en otros servidores.
El equilibrador también deja de enviar tráfico de usuarios a servidores inactivos, pero continúa verificando su estado.

Cuando el servidor está disponible, comienza a responder a /silbido. Tan pronto como comienzan a llegar respuestas normales a los pings de servidores inactivos, los balanceadores comienzan a enviar tráfico de usuarios allí. Se restablece el funcionamiento del clúster, hurra.

Peor aún: muchos servidores no están disponibles

Una parte importante de los servidores del centro de datos están cortados. ¿Qué hacer, dónde correr? El equilibrador vuelve al rescate. Cada balanceador almacena constantemente en la memoria el número actual de servidores activos. Calcula constantemente la cantidad máxima de tráfico que puede procesar el centro de datos actual.

Cuando muchos servidores en un centro de datos fallan, el equilibrador se da cuenta de que este centro de datos no puede procesar todo el tráfico.

Luego, el exceso de tráfico comienza a distribuirse aleatoriamente a otros centros de datos. Todo funciona, todos están contentos.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Cómo lo hacemos: publicar lanzamientos

Ahora hablemos de cómo publicamos los cambios realizados en el servicio. Aquí hemos tomado el camino de simplificar los procesos: el lanzamiento de una nueva versión está casi completamente automatizado.
Cuando se acumula una cierta cantidad de cambios en el proyecto, se crea automáticamente una nueva versión y comienza su compilación.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Luego, el servicio se lanza a pruebas, donde se verifica la estabilidad de la operación.

Al mismo tiempo, se inician las pruebas automáticas de rendimiento. De esto se encarga un servicio especial. No hablaré de ello ahora; su descripción merece un artículo aparte.

Si la publicación en pruebas tiene éxito, se inicia automáticamente la publicación de la versión en preestable. Prestable es un clúster especial al que se dirige el tráfico normal de usuarios. Si devuelve un error, el equilibrador realiza una nueva solicitud a producción.

En preestable, los tiempos de respuesta se miden y se comparan con la versión anterior en producción. Si todo está bien, entonces una persona se conecta: verifica los gráficos y los resultados de las pruebas de carga y luego comienza la implementación en producción.

Todo lo mejor para el usuario: pruebas A/B

No siempre es obvio si los cambios en un servicio traerán beneficios reales. Para medir la utilidad de los cambios, a la gente se le ocurrieron pruebas A/B. Te contaré un poco cómo funciona en la búsqueda de Yandex.Market.

Todo comienza agregando un nuevo parámetro CGI que habilita nuevas funciones. Sea nuestro parámetro: mercado_nueva_funcionalidad=1. Luego, en el código habilitamos esta funcionalidad si la bandera está presente:

If (cgi.experiments.market_new_functionality) {
// enable new functionality
}

Se están implementando nuevas funciones en producción.

Para automatizar las pruebas A/B, existe un servicio dedicado que proporciona información detallada. descrito aquí. Se crea un experimento en el servicio. La cuota de tráfico se establece, por ejemplo, en un 15%. Los porcentajes no se establecen para consultas, sino para usuarios. También se indica la duración del experimento, por ejemplo, una semana.

Se pueden realizar varios experimentos simultáneamente. En la configuración puede especificar si es posible la intersección con otros experimentos.

Como resultado, el servicio agrega automáticamente un argumento. mercado_nueva_funcionalidad=1 al 15% de los usuarios. También calcula automáticamente las métricas seleccionadas. Una vez completado el experimento, los analistas analizan los resultados y sacan conclusiones. En función de los hallazgos, se toma la decisión de implementarlo en producción o refinarlo.

La mano hábil del mercado: pruebas en producción

A menudo sucede que necesita probar el funcionamiento de una nueva funcionalidad en producción, pero no está seguro de cómo se comportará en condiciones de "combate" bajo una carga pesada.

Hay una solución: los indicadores en los parámetros CGI se pueden usar no solo para pruebas A/B, sino también para probar nuevas funciones.

Creamos una herramienta que le permite cambiar instantáneamente la configuración en miles de servidores sin exponer el servicio a riesgos. Se llama Detener toque. La idea original era poder desactivar rápidamente algunas funciones sin un diseño. Luego la herramienta se expandió y se volvió más compleja.

El diagrama de flujo del servicio se presenta a continuación:

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Los valores de las banderas se establecen a través de la API. El servicio de gestión almacena estos valores en la base de datos. Todos los servidores van a la base de datos una vez cada diez segundos, generan valores de bandera y aplican estos valores a cada solicitud.

En el toque Detener puedes establecer dos tipos de valores:

1) Expresiones condicionales. Aplicar cuando uno de los valores sea verdadero. Por ejemplo:

{
	"condition":"IS_DC1",
	"value":"3",
}, 
{
	"condition": "CLUSTER==2 and IS_BERU", 
	"value": "4!" 
}

El valor "3" se aplicará cuando la solicitud se procese en la ubicación DC1. Y el valor es "4" cuando la solicitud se procesa en el segundo clúster del sitio beru.ru.

2) Valores incondicionales. Aplicar de forma predeterminada si no se cumple ninguna de las condiciones. Por ejemplo:

valor, valor!

Si un valor termina con un signo de exclamación, se le da mayor prioridad.

El analizador de parámetros CGI analiza la URL. Luego aplica los valores del Stop Tap.

Se aplican valores con las siguientes prioridades:

  1. Con mayor prioridad desde Stop Tap (signo de exclamación).
  2. El valor de la solicitud.
  3. Valor predeterminado de Detener toque.
  4. Valor predeterminado en el código.

Hay muchas banderas que se indican en valores condicionales; son suficientes para todos los escenarios que conocemos:

  • Centro de datos.
  • Entorno: producción, pruebas, sombra.
  • Lugar: mercado, beru.
  • Número de grupo.

Con esta herramienta, puede habilitar nuevas funciones en un determinado grupo de servidores (por ejemplo, en un solo centro de datos) y probar el funcionamiento de esta funcionalidad sin ningún riesgo particular para todo el servicio. Incluso si cometió un error grave en alguna parte, todo comenzó a fallar y todo el centro de datos se vino abajo, los equilibradores redirigirán las solicitudes a otros centros de datos. Los usuarios finales no notarán nada.

Si nota un problema, puede devolver inmediatamente la bandera a su valor anterior y los cambios se revertirán.

Este servicio también tiene sus desventajas: a los desarrolladores les encanta y, a menudo, intentan introducir todos los cambios en Stop Tap. Estamos tratando de combatir el mal uso.

El enfoque Stop Tap funciona bien cuando ya tiene un código estable listo para implementarse en producción. Al mismo tiempo, todavía tienes dudas y quieres comprobar el código en condiciones de "combate".

Sin embargo, Stop Tap no es adecuado para realizar pruebas durante el desarrollo. Hay un clúster separado para desarrolladores llamado "clúster en la sombra".

Prueba secreta: grupo de sombras

Las solicitudes de uno de los clústeres se duplican en el clúster oculto. Pero el equilibrador ignora por completo las respuestas de este grupo. El diagrama de su funcionamiento se presenta a continuación.

Cómo funciona la búsqueda de Yandex.Market y qué sucede si uno de los servidores falla

Obtenemos un grupo de prueba que se encuentra en condiciones reales de "combate". El tráfico normal de usuarios va allí. El hardware en ambos clústeres es el mismo, por lo que se pueden comparar el rendimiento y los errores.

Y dado que el equilibrador ignora por completo las respuestas, los usuarios finales no verán las respuestas del clúster oculto. Por tanto, no da miedo cometer un error.

Hallazgos

Entonces, ¿cómo construimos la búsqueda de mercado?

Para que todo funcione sin problemas, separamos la funcionalidad en servicios separados. De esta manera podemos escalar solo aquellos componentes que necesitamos y simplificarlos. Es fácil asignar un componente independiente a otro equipo y compartir las responsabilidades de trabajar en él. Y un ahorro significativo de hierro con este enfoque es una ventaja obvia.

El cluster en la sombra también nos ayuda: podemos desarrollar servicios, probarlos en el proceso y no molestar al usuario.

Bueno, probando en producción, por supuesto. ¿Necesita cambiar la configuración en miles de servidores? Fácil, usa Stop Tap. De esta manera, puede implementar inmediatamente una solución compleja ya preparada y volver a una versión estable si surgen problemas.

Espero haber podido mostrar cómo hacemos que el mercado sea rápido y estable con una base de ofertas en constante crecimiento. Cómo solucionamos los problemas del servidor, atendemos una gran cantidad de solicitudes, mejoramos la flexibilidad del servicio y lo hacemos sin interrumpir los procesos de trabajo.

Fuente: habr.com

Añadir un comentario