Optimización de carga en un proyecto Highload con ElasticSearch

Hola Habr! Mi nombre es Maxim Vasiliev, trabajo como analista y gerente de proyectos en FINCH. Hoy me gustaría contarles cómo, con la ayuda de ElasticSearch, pudimos procesar 15 millones de consultas en 6 minutos y optimizar la carga diaria en el sitio de uno de nuestros clientes. Desafortunadamente, tendremos que prescindir de los nombres, ya que tenemos el NDA, esperamos que el contenido del artículo no se vea afectado. Vamos

Cómo se organiza el proyecto


En nuestro backend, creamos servicios que garantizan el rendimiento de los sitios y las aplicaciones móviles de nuestro cliente. La estructura general se puede ver en el diagrama:

imagen

en el proceso, procesamos una gran cantidad de transacciones: compras, pagos, operaciones con saldos de usuarios, para los cuales almacenamos muchos registros, y también importamos y exportamos estos datos a sistemas externos.

También hay procesos inversos cuando recibimos datos de un cliente y los transmitimos al usuario. Además, todavía hay procesos para trabajar con pagos y programas de bonificación.

Fondo corto


Inicialmente, utilizamos PostgreSQL como el único almacén de datos. Sus ventajas estándar para DBMS: disponibilidad de transacciones, lenguaje desarrollado de muestreo de datos, herramientas amplias para la integración; Junto con un buen rendimiento, las personas satisfechas han satisfecho nuestras necesidades durante mucho tiempo.

Almacenamos absolutamente todos los datos en Postgres: desde transacciones hasta noticias. Pero el número de usuarios creció, y con él el número de solicitudes.

Para comprender, el número anual de sesiones en 2017 solo en el sitio de escritorio es de 131 millones. En 2018, 125 millones en 2019 son nuevamente 130 millones. Agregue otros 100-200 millones de la versión móvil del sitio y la aplicación móvil, y recibirá una gran cantidad de solicitudes.

Con el crecimiento del proyecto, Postgres dejó de hacer frente a la carga, no tuvimos tiempo, apareció una gran cantidad de consultas diferentes, bajo las cuales no pudimos crear una cantidad suficiente de índices.

Nos dimos cuenta de que había una necesidad de otros almacenes de datos que pudieran satisfacer nuestras necesidades y eliminar la carga de PostgreSQL. Elasticsearch y MongoDB se consideraron como posibles opciones. Este último perdió en los siguientes puntos:

  1. Velocidad de indexación lenta con aumento del volumen de datos en los índices. La velocidad de Elastic es independiente de la cantidad de datos.
  2. Sin búsqueda de texto completo

Así que elegimos Elastic para nosotros y nos preparamos para la transición.

Cambiar a elástico


1. Comenzamos la transición con un servicio de búsqueda en el punto de venta. Nuestro cliente tiene un total de aproximadamente 70,000 puntos de venta, y requiere varios tipos de búsquedas en el sitio y en la aplicación:

  • Búsqueda de texto por nombre de ciudad
  • Geo-búsqueda en un radio dado desde algún punto. Por ejemplo, si un usuario quiere ver qué puntos de venta están más cerca de su hogar.
  • Buscar por un cuadrado determinado: el usuario dibuja un cuadrado en el mapa y se le muestran todos los puntos en este radio.
  • Busca filtros adicionales. Los puntos de venta difieren entre sí en el surtido

Hablando de organización, en Postgres tenemos una fuente de datos tanto en el mapa como en las noticias, y en Elastic Snapshots se hacen a partir de los datos originales. El hecho es que inicialmente Postgres no pudo hacer frente a la búsqueda por todos los criterios. No solo había muchos índices, sino que también podían cruzarse, por lo que el programador de Postgres se perdió y no entendió qué índice usar para él.

2. El siguiente en la fila fue la sección de noticias. Todos los días, las publicaciones aparecen en el sitio para que el usuario no se pierda en el flujo de información, los datos deben ordenarse antes de emitirse. Para esto, necesita una búsqueda: en el sitio puede buscar por coincidencia de texto y, al mismo tiempo, conectar filtros adicionales, ya que también se realizan a través de Elastic.

3. Luego trasladamos el procesamiento de la transacción. Los usuarios pueden comprar un producto específico en el sitio y participar en el sorteo. Después de tales compras, procesamos una gran cantidad de datos, especialmente los fines de semana y feriados. A modo de comparación, si en días normales el número de compras oscila entre 1,5 y 2 millones, en vacaciones la cifra puede alcanzar los 53 millones.

Al mismo tiempo, los datos deben procesarse en un tiempo mínimo; a los usuarios no les gusta esperar un resultado durante varios días. No logrará dichos plazos a través de Postgres: a menudo recibimos bloqueos y, aunque procesamos todas las solicitudes, los usuarios no pudieron verificar si recibieron premios o no. Esto no es muy agradable para el negocio, por lo que trasladamos el procesamiento a Elasticsearch.

Periodicidad


Ahora las actualizaciones se configuran en función de los eventos, en las siguientes condiciones:

  1. Punto de venta. Tan pronto como nos llegan datos de una fuente externa, comenzamos inmediatamente la actualización.
  2. Noticias. Tan pronto como se edita cualquier noticia en el sitio, se envía automáticamente a Elastic.

Aquí nuevamente, vale la pena mencionar las ventajas de Elastic. En Postgres, al enviar una solicitud, debe esperar hasta que honestamente procese todos los registros. Puede enviar 10 mil registros a Elastic e inmediatamente comenzar a trabajar, sin esperar hasta que los registros se distribuyan en todos los fragmentos. Por supuesto, algunos fragmentos o réplicas pueden no ver los datos de inmediato, pero muy pronto todo estará disponible.

Metodos de Integracion


Hay 2 formas de integrarse con Elastic:

  1. A través del cliente nativo sobre TCP. El controlador nativo está desapareciendo gradualmente: ya no es compatible, tiene una sintaxis muy inconveniente. Por lo tanto, prácticamente no lo usamos e intentamos abandonarlo por completo.
  2. A través de una interfaz HTTP en la que puede utilizar tanto las solicitudes JSON como la sintaxis de Lucene. Este último es un motor de texto que usa Elastic. En esta opción, tenemos la capacidad de Batch a través de solicitudes JSON a través de HTTP. Esta es la opción que estamos tratando de usar.

Gracias a la interfaz HTTP, podemos usar bibliotecas que proporcionan una implementación asincrónica del cliente HTTP. Podemos aprovechar Batch y la API asincrónica, que al final ofrece un alto rendimiento, lo que ayudó mucho en los días de una gran acción (más sobre eso a continuación).

Algunos números para comparar:

  • Ahorro de usuarios que recibieron premios en Postgres en 20 transmisiones sin agrupaciones: 460,713 entradas en 42 segundos
  • Cliente elástico + reactivo para 10 subprocesos + lote para 1000 elementos: 596749 registros en 11 segundos
  • Cliente elástico + reactivo para 10 subprocesos + lote para 1000 elementos: 23801684 registros en 4 minutos

Ahora hemos escrito un administrador de solicitudes HTTP que crea JSON como Batch / not Batch y lo envía a través de cualquier cliente HTTP, independientemente de la biblioteca. También puede optar por enviar solicitudes de forma sincrónica o asincrónica.

En algunas integraciones, todavía utilizamos el cliente de transporte oficial, pero esto es solo una cuestión de refactorización. Al mismo tiempo, se utiliza un cliente personalizado creado sobre la base de Spring WebClient para el procesamiento.

imagen

Gran promoción


Una vez al año, se lleva a cabo una gran campaña para los usuarios en el proyecto: este es el mismo Highload, ya que en este momento trabajamos con decenas de millones de usuarios al mismo tiempo.

Por lo general, las cargas máximas ocurren durante las vacaciones, pero esta promoción es un nivel completamente diferente. El año anterior, el día de la promoción, vendimos 27,580,890 unidades de bienes. Los datos se procesaron durante más de media hora, lo que causó molestias a los usuarios. Los usuarios recibieron premios por participar, pero quedó claro que el proceso debía acelerarse.

A principios de 2019, decidimos que necesitábamos ElasticSearch. Durante todo un año, organizamos el procesamiento de los datos recibidos en Elastic y su salida en la API de la aplicación móvil y el sitio. Como resultado, al año siguiente durante la campaña procesamos 15 131 783 registros en 6 minutos.

Dado que tenemos muchas personas que desean comprar productos y participar en el sorteo de premios en promociones, esta es una medida temporal. Ahora estamos enviando información relevante a Elastic, pero en el futuro planeamos transferir información de archivo de los últimos meses a Postgres como un depósito permanente. Para no obstruir el índice Elastic, que también tiene sus limitaciones.

Conclusión / Conclusiones


Por el momento, hemos transferido a Elastic todos los servicios que queríamos y hemos detenido por ahora. Ahora estamos creando un índice en Elastic sobre el almacenamiento principal persistente en Postgres, que asume la carga del usuario.

En el futuro, planeamos transferir servicios si entendemos que la solicitud de datos se vuelve demasiado diversa y es buscada por un número ilimitado de columnas. Esto ya no es una tarea para Postgres.

Si necesitamos una búsqueda de texto completo en el funcional, o si tenemos muchos criterios de búsqueda diferentes, entonces ya sabemos que esto debe traducirse a Elastic.

⌘⌘⌘


Gracias por leer. Si su empresa también utiliza ElasticSearch y tiene sus propios casos de implementación, infórmenos. Será interesante saber cómo otros lo han hecho :-)

All Articles