¿Cómo sobrevivimos al fuerte aumento de la carga x10 en el sitio remoto y qué conclusiones hicieron?

Hola Habr! Los últimos dos meses hemos vivido en una situación muy interesante, y me gustaría compartir nuestra historia de escalamiento de infraestructura. Durante este tiempo, SberMarket creció 4 veces en pedidos y lanzó un servicio en 17 nuevas ciudades. El crecimiento explosivo de la demanda de entrega de alimentos nos ha obligado a escalar nuestra infraestructura. Lea los hallazgos más interesantes y útiles debajo del gato.



Mi nombre es Dima Bobylev, soy el Director Técnico de SberMarket. Como esta es la primera publicación en nuestro blog, diré algunas palabras sobre mí y sobre la empresa. El otoño pasado, participé en el concurso de jóvenes líderes del Runet. Para el concurso, escribí una historia corta sobre cómo nosotros en SberMarket vemos la cultura interna y el enfoque para el desarrollo del servicio. Y aunque no fue posible ganar la competencia, formulé para mí los principios básicos para el desarrollo del ecosistema de TI.

Al administrar un equipo, es importante comprender y encontrar un equilibrio entre lo que la empresa necesita y las necesidades de cada desarrollador específico. Ahora SberMarket está creciendo 13 veces año tras año, y esto afecta al producto, lo que requiere un aumento constante en el volumen y el ritmo de desarrollo. A pesar de esto, dedicamos suficiente tiempo a los desarrolladores para el análisis preliminar y la escritura de códigos de alta calidad. El enfoque formado ayuda no solo a crear un producto que funcione, sino también a su mayor escala y desarrollo. Como resultado de este crecimiento, SberMarket ya se ha convertido en un líder entre los servicios de entrega de alimentos: entregamos alrededor de 18 mil pedidos al día todos los días, aunque a principios de febrero había unos 3.500 de ellos.


Una vez que un cliente le pidió al servicio de mensajería de SberMarket que le entregara productos sin contacto, directamente al balcón

Pero pasemos a los detalles. En los últimos meses, hemos estado escalando activamente la infraestructura de nuestra empresa. Tal necesidad fue explicada por factores externos e internos. Simultáneamente con la expansión de la base de clientes, el número de tiendas conectadas aumentó de 90 a principios de año a más de 200 a mediados de mayo. Por supuesto, preparamos, reservamos la infraestructura principal y contamos con la posibilidad de escalado vertical y horizontal de todas las máquinas virtuales ubicadas en la nube Yandex. Sin embargo, la práctica ha demostrado: "Todo lo que puede salir mal sale mal". Y hoy quiero compartir las situaciones más interesantes que han sucedido en estas semanas. Espero que nuestra experiencia te sea útil.

Esclavo en alerta completa


Incluso antes de que comenzara la pandemia, nos enfrentamos a un aumento en el número de solicitudes a nuestros servidores de back-end. La tendencia a pedir productos con entrega a domicilio comenzó a cobrar impulso, y con la introducción de las primeras medidas de autoaislamiento en relación con COVID-19, la carga creció drásticamente ante nuestros ojos todo el día. Era necesario descargar rápidamente los servidores maestros de la base de datos principal y transferir parte de las solicitudes de lectura a los servidores de réplica (esclavos).

Nos estábamos preparando de antemano para este paso, y para tal maniobra ya se habían lanzado 2 servidores esclavos. Trabajaron principalmente en tareas por lotes para generar fuentes de información para intercambiar datos con socios. Estos procesos crearon una carga adicional y con bastante razón se pusieron "fuera de los corchetes" un par de meses antes. 

Como hubo replicación en Slave, nos adherimos al concepto de que las aplicaciones solo pueden trabajar con ellas en modo de solo lectura. El Plan de recuperación ante desastres sugirió que, en caso de un desastre, podríamos simplemente montar el Esclavo en lugar del Maestro y cambiar todas las solicitudes de escritura y lectura al Esclavo. Sin embargo, también queríamos usar réplicas para las necesidades del departamento de análisis, por lo que los servidores no se transfirieron completamente al estado de solo lectura, y cada host tenía su propio conjunto de usuarios, y algunos tenían permisos de escritura para guardar resultados de cálculo intermedios.

Hasta cierto nivel de carga, teníamos suficientes asistentes para escribir y leer al procesar solicitudes http. A mediados de marzo, justo cuando Sbermarket decidió cambiar completamente a un sitio remoto, comenzamos un aumento múltiple en RPS. Cada vez más de nuestros clientes fueron al autoaislamiento o al trabajo desde casa, lo que se reflejó en los indicadores de carga.

El rendimiento del "maestro" ya no era suficiente, por lo que comenzamos a soportar algunas de las solicitudes de lectura más pesadas para una réplica. Para enviar de manera transparente solicitudes para escribir al maestro y leer al esclavo, utilizamos la gema de rubí " Octopus". Creamos un usuario especial con el postfix _readonly sin permisos de escritura. Pero debido a un error en la configuración de uno de los hosts, parte de las solicitudes de escritura se enviaron al servidor esclavo en nombre de un usuario que tenía los derechos correspondientes.

El problema no se manifestó de inmediato, porque El aumento de la carga aumentó el retraso del esclavo. La inconsistencia de los datos se reveló en la mañana cuando, después de las importaciones nocturnas, los esclavos no "alcanzaron" al maestro. Atribuimos esto a la gran carga del servicio en sí y a la importación asociada con el lanzamiento de nuevas tiendas. Pero para dar información a las muchas horas de retraso es inaceptable, y que pasó a la segunda procesos analíticos del esclavo, porque se había utilizado en los recursos lshie y no fue cargado solicitudes de lectura (y hemos explicado a nosotros mismos a la ausencia de retraso de la replicación).

Cuando descubrimos las razones para el "deslizamiento" del esclavo principal, la analítica ya falló por la misma razón. A pesar de la presencia de dos servidores adicionales, a los que planeamos transferir la carga en caso de un bloqueo maestro, debido a un desafortunado error, resultó que en un momento crítico no hay ninguno.

Pero dado que no solo volcamos la base de datos (el resto en ese momento era de aproximadamente 5 horas), sino también un servidor maestro de instantáneas, logramos iniciar la réplica en 2 horas. Es cierto que después de eso se esperaba que rodamos el registro de replicación durante mucho tiempo (porque el proceso está en modo de subproceso único, pero esta es una historia completamente diferente).

: , readonly . , .

« »


Aunque actualizamos constantemente el catálogo en el sitio, las solicitudes que realizamos a los servidores Slave permitieron un ligero retraso de Master. El tiempo durante el cual descubrimos y eliminamos el problema de "abandonar repentinamente la distancia" de los esclavos fue más que una "barrera psicológica" (durante este tiempo los precios podrían haberse actualizado y los clientes habrían visto datos obsoletos), y tuvimos que cambiar todas las solicitudes al servidor de la base de datos principal. . Como resultado, el sitio funcionó lentamente ... pero al menos funcionó. Y mientras el Esclavo se recuperaba, no tuvimos más remedio que optimizar. 

Mientras los servidores Slave se recuperaban, los minutos se alargaban lentamente, el Master permaneció sobrecargado y dedicamos todos nuestros esfuerzos a optimizar las tareas activas de acuerdo con la Regla de Pareto: seleccionamos las solicitudes TOP que dan la mayor parte de la carga y comenzamos a ajustar. Esto se hizo directamente "sobre la marcha".

Un efecto interesante fue que MySQL cargado en el globo ocular responde incluso a una ligera mejora en los procesos. La optimización de un par de solicitudes, que dieron solo el 5% de la carga total, ya mostraban una descarga tangible de la CPU. Como resultado, pudimos proporcionar un suministro aceptable de recursos para que Master trabaje con la base de datos y obtenga el tiempo necesario para restaurar las réplicas. 

Conclusión: Incluso una pequeña optimización le permite "sobrevivir" durante la sobrecarga durante varias horas. Esto fue suficiente para nosotros durante la recuperación de servidores con réplicas. Por cierto, discutiremos el lado técnico de la optimización de consultas en una de las siguientes publicaciones. Suscríbete a nuestro blog si te puede ser útil.

Organizar el monitoreo del desempeño de los servicios asociados.


Estamos involucrados en el procesamiento de pedidos de clientes y, por lo tanto, nuestros servicios interactúan constantemente con API de terceros: estas son puertas de enlace para enviar SMS, plataformas de pago, sistemas de enrutamiento, geocodificador, el Servicio de Impuestos Federales y muchos otros sistemas. Y cuando la carga comenzó a crecer rápidamente, comenzamos a descansar en contra de las limitaciones API de nuestros socios de servicio, que ni siquiera habíamos pensado antes.

El exceso inesperado de cuotas para los servicios de afiliación puede ocasionar su propio tiempo de inactividad. Muchas API bloquean clientes que exceden los límites y, en algunos casos, un exceso de solicitudes puede sobrecargar la producción con un socio. 

Por ejemplo, al momento de aumentar el número de entregas, los servicios que lo acompañan no pudieron hacer frente a las tareas de su distribución, determinación de rutas. Como resultado, resultó que los pedidos se hicieron y el servicio que crea la ruta no funciona. Debo decir que nuestros especialistas en logística lo hicieron casi imposible bajo estas condiciones, y la clara interacción del equipo ayudó a compensar las fallas temporales del servicio. Pero tal volumen de aplicaciones es imposible de procesar manualmente, y después de algún tiempo nos encontraríamos con una brecha inaceptable entre las órdenes y su ejecución. 

Se tomaron varias medidas organizativas y el trabajo coordinado del equipo ayudó a ganar tiempo mientras acordamos nuevas condiciones y esperamos la modernización de los servicios de algunos socios. Hay otras API que lo complacen con una alta resistencia y tarifas impías en caso de alto tráfico. Por ejemplo, al principio utilizamos una API de mapeo conocida para determinar la dirección de un punto de entrega. Pero a finales de mes recibieron una factura ordenada de casi 2 millones de rublos. Después de eso, decidieron reemplazarlo rápidamente. No participaré en publicidad, pero diré que nuestros gastos han disminuido significativamente.

: . , « », , . , ,   . 

, « » ()


Estamos acostumbrados a "enchufar" en la base de datos principal o en los servidores de aplicaciones, pero al escalar, pueden aparecer problemas donde no se esperaban. Para la búsqueda de texto completo en el sitio, utilizamos el motor Apache Solr. Con un aumento en la carga, notamos una disminución en el tiempo de respuesta y la carga del procesador del servidor alcanzó el 100%. Lo que podría ser más simple: le daremos más recursos al contenedor con Solr.

En lugar de la ganancia de rendimiento esperada, el servidor simplemente "murió". Inmediatamente se cargó al 100% y respondió aún más lentamente. Inicialmente, teníamos 2 núcleos y 2 GB de RAM. Decidimos hacer lo que generalmente ayuda: le dimos al servidor 8 núcleos y 32 GB. Todo se ha vuelto mucho peor (exactamente cómo y por qué, lo diremos en una publicación separada). 

Durante varios días, descubrimos las complejidades de este problema y logramos un rendimiento óptimo con 8 núcleos y 32 GB. Esta configuración nos permite continuar aumentando la carga hoy, lo cual es muy importante porque el crecimiento no es solo en términos de clientes, sino también en el número de tiendas conectadas: en 2 meses su número se ha duplicado. 

Conclusión: Los métodos estándar como "agregar más hierro" no siempre funcionan. Entonces, al escalar cualquier servicio, debe comprender bien cómo usa los recursos y probar previamente su funcionamiento en nuevas condiciones. 

Sin estado: la clave para una fácil escala horizontal


En general, nuestro equipo se adhiere a un enfoque bien conocido: los servicios no deben tener estado sin estado y deben ser independientes del entorno de tiempo de ejecución. Esto nos permitió sobrevivir al crecimiento de la carga mediante una simple escala horizontal. Pero tuvimos una excepción de servicio: un controlador para tareas en segundo plano largas. Se dedicaba a enviar correos electrónicos y sms, procesar eventos, generar feeds, importar precios y acciones, y procesar imágenes. Sucedió que dependía del almacenamiento local de archivos y estaba en una sola copia. 

Cuando aumentó el número de tareas en la cola del procesador (y esto sucedió naturalmente con un aumento en el número de pedidos), el rendimiento del host que aloja el procesador y el almacenamiento de archivos se convirtió en un factor limitante. Como resultado, se detuvo la actualización del surtido y los precios, el envío de notificaciones a los usuarios y muchas otras funciones críticas atascadas en la cola. El equipo de Ops migró rápidamente el almacenamiento de archivos a un almacenamiento de red similar a S3, y esto nos permitió generar varias máquinas potentes para escalar el controlador de tareas en segundo plano.

Conclusión: la regla sin estado debe respetarse para todos los componentes, sin excepción, incluso si parece "que definitivamente no nos estamos molestando". Es mejor dedicar un poco de tiempo a la organización correcta del trabajo de todos los sistemas que reescribir el código rápidamente y reparar el servicio que está experimentando una sobrecarga.

7 principios para un crecimiento intenso


A pesar de la disponibilidad de capacidad adicional, en el proceso de crecimiento pisamos algunos rastrillos. Durante este tiempo, el número de pedidos aumentó más de 4 veces. Ahora ya entregamos más de 17,000 pedidos por día en 62 ciudades y planeamos expandir nuestra geografía aún más: en el primer semestre de 2020, se espera que el servicio se lance en toda Rusia. Para hacer frente a la creciente carga, teniendo en cuenta los baches ya completos, hemos desarrollado por nosotros mismos 7 principios básicos de trabajo en condiciones de crecimiento constante:

  1. -. Jira,   . . — . , , , , .
  2. . « » . , , . , .
  3. . -, . -, , .
  4. stateless. , . . , , S3. https://12factor.net. , .
  5. . , . , , - . , . 
  6. . , . , SMS . , .
  7. . , . , , . API, -. .


No sin pérdidas, pero sobrevivimos a esta etapa, y hoy tratamos de cumplir con todos los principios encontrados, y cada máquina tiene la capacidad de aumentar fácilmente el rendimiento x4 para hacer frente a cualquier sorpresa. 

En las siguientes publicaciones, compartiremos nuestra experiencia en la investigación del hundimiento del rendimiento en Apache Solr, y hablaremos sobre la optimización de consultas y cómo la interacción con el Servicio de Impuestos Federales ayuda a la empresa a ahorrar dinero. Suscríbase a nuestro blog para que no se pierda nada y díganos en los comentarios si tuvo problemas durante el crecimiento del tráfico.


All Articles