Cómo dejar de preocuparte y empezar a vivir sin un monolito





A todos nos encantan las historias. Nos gusta sentarnos junto al fuego y hablar sobre nuestras victorias pasadas, batallas o simplemente sobre nuestra experiencia laboral.



Hoy es uno de esos días. E incluso si no estás junto al fuego ahora, pero tenemos una historia para ti. La historia de cómo empezamos a trabajar con almacenamiento en Tarantool.



Érase una vez en nuestra empresa un par de "monolitos" y un "techo" para todos, al que estos monolitos se acercaban lenta pero segura, limitando la fuga de nuestra empresa, nuestro desarrollo. Y hubo un entendimiento inequívoco: un día golpearemos con fuerza este techo.



Es ahora cuando estamos dominados por la ideología de dividir todo y a todos, desde el equipo hasta la lógica empresarial. Como resultado, tenemos, por ejemplo, dos CD que son prácticamente independientes a nivel de red. Y luego todo fue completamente diferente.



Hoy en día, hay un montón de herramientas y herramientas para realizar cambios en forma de CI / CD, K8S, etc. En la época "monolítica", no necesitábamos tantas palabras extranjeras. Bastaba con arreglar el "almacenamiento" en la base de datos.



Pero el tiempo pasó, y el número de solicitudes avanzó con él, a veces disparando RPS más allá de nuestras capacidades. Con la entrada en el mercado de los países de la CEI, la carga en el procesador de la base de datos del primer monolito no cayó por debajo del 90% y el RPS se mantuvo en el nivel de 2400. Y estos no eran solo selectores pequeños, sino consultas importantes con un montón de comprobaciones y JOIN que se podían ejecutar casi la mitad de los datos en el fondo de un gran IO.



Cuando las ventas en toda regla del Black Friday comenzaron a aparecer en el escenario, y Wildberries comenzó a considerarlas como una de las primeras en Rusia, la situación se volvió completamente triste. Después de todo, la carga en esos días se triplica.

¡Oh, estos "tiempos monolíticos"! Estoy seguro de que se ha encontrado con algo similar y aún no puede comprender cómo le pudo pasar esto.



¿Qué puedes hacer? La moda es inherente a la tecnología. Hace 5 años, tuvimos que repensar una de estas modificaciones en la forma de un sitio existente en .NET y MS SQL-server, que mantuvo cuidadosamente toda la lógica del sitio en sí. Lo mantuvo con tanto cuidado que cortar tal monolito resultó ser un placer largo y bastante difícil.

Una pequeña digresión.



En varios eventos, digo: "¡Si no viste el monolito, entonces no creciste!" Me interesa tu opinión al respecto, escríbela, por favor, en los comentarios.



Un sonido de trueno



Volvamos a nuestra "hoguera". Para distribuir la carga de funcionalidad "monolítica", decidimos dividir el sistema en microservicios basados ​​en tecnologías de código abierto. Porque, al menos, son más baratos de escalar. Y el entendimiento de que tendríamos que escalar (y mucho) fue del 100%. De hecho, ya en ese momento resultó ingresar a los mercados de los países vecinos, y el número de registros, así como el número de pedidos, comenzó a crecer aún más.



Después de analizar los primeros solicitantes para dejar el monolito en microservicios, nos dimos cuenta de que en el 80% de ellos, el 99% escriben desde los sistemas de back office y leen desde los sistemas de front-end. En primer lugar, esto se refería a un par de subsistemas importantes para nosotros: los datos del usuario y el sistema para calcular el costo final de los productos en función de la información sobre cupones y descuentos de clientes adicionales.



Sangrar. Ahora da miedo imaginarlo, pero además de los subsistemas antes mencionados, también se sacaron de nuestro monolito catálogos de productos, una cesta de usuarios, un sistema de búsqueda de productos, un sistema de filtrado para catálogos de productos y varios sistemas de recomendación. Para el funcionamiento de cada uno de ellos, hay clases separadas de sistemas estrechamente afilados, pero en un momento todos vivieron en una "casita".



Planeamos transferir datos sobre nuestros clientes a un sistema fragmentado. La eliminación de la funcionalidad para calcular el costo final de los bienes requirió una buena escalabilidad de lectura, porque creó la mayor carga de RPS y fue la más difícil de implementar para la base de datos (muchos datos están involucrados en el proceso de cálculo).



Como resultado, tenemos un esquema que funciona bien con Tarantool.



En ese momento, para la operación de microservicios, se eligieron esquemas de trabajo con múltiples centros de datos en máquinas virtuales y hardware. Como se muestra en las figuras, las opciones de replicación de Tarantool se aplicaron en los modos maestro-maestro y maestro-esclavo.





Arquitectura. Opción 1. Servicio de usuario



En el momento actual hay 24 fragmentos, cada uno de los cuales tiene 2 instancias (una para cada DC), todas en modo maestro-maestro.



En la parte superior de la base de datos hay aplicaciones que acceden a las réplicas de la base de datos. Las aplicaciones funcionan con Tarantool a través de nuestra biblioteca personalizada, que implementa la interfaz del controlador Tarantool Go. Ve todas las réplicas y puede trabajar con el maestro para leer y escribir. De hecho, implementa el modelo de conjunto de réplicas, que agrega la lógica para seleccionar réplicas, realizar reintentos, un disyuntor y límite de velocidad.



Al mismo tiempo, es posible configurar la política de elegir una réplica en el contexto de un fragmento. Por ejemplo, roundrobin.





Arquitectura. Opción 2. Servicio de cálculo del costo final de la mercancía



Hace varios meses, la mayoría de las solicitudes para el cálculo del costo final de la mercadería fueron a un nuevo servicio, que, en principio, funciona sin bases de datos, pero hace un tiempo fue procesado al 100% por el servicio con Tarantool under the hood.



La base de datos del servicio consta de 4 maestros en los que el sincronizador recopila datos y cada uno de estos maestros de replicación distribuye datos a réplicas de solo lectura. Cada maestro tiene unas 15 líneas de este tipo.



Tanto en el primero como en el segundo esquema, si un DC no está disponible, la aplicación puede recibir datos en el segundo.



Cabe señalar que la replicación en Tarantool es bastante flexible y configurable en tiempo de ejecución. En otros sistemas, ha habido dificultades. Por ejemplo, cambiar los parámetros max_wal_senders y max_replication_slots en PostgreSQL requiere que se reinicie el asistente, lo que en algunos casos puede provocar una desconexión entre la aplicación y el DBMS.



¡Busca y encontraras!



¿Por qué no lo hicimos "como gente normal", sino que elegimos una forma atípica? Depende de lo que se considere normal. Muchas personas generalmente crean un clúster a partir de Mongo y lo distribuyen en tres DC distribuidos geográficamente.



En ese momento, ya teníamos dos proyectos en Redis. El primero es un caché y el segundo es un almacenamiento persistente para datos no demasiado críticos. Fue bastante difícil con él, en parte por culpa nuestra. A veces, lo importante eran volúmenes bastante grandes y, de vez en cuando, el sitio se sentía mal. Usamos este sistema en la versión maestro-esclavo. Y hubo muchos casos en que algo le sucedió al maestro y se rompió la réplica.



Es decir, Redis es bueno para tareas sin estado, no con estado. En principio, permitió resolver la mayoría de los problemas, pero solo si se trataba de soluciones clave-valor con un par de índices. Pero en ese momento, Redis estaba bastante triste por la persistencia y la replicación. Además, hubo quejas sobre el desempeño.



Pensando en MySQL y PostgreSQL. Pero el primero de alguna manera no echó raíces con nosotros, y el segundo es un producto bastante sofisticado en sí mismo, y sería inapropiado construir servicios simples sobre él.

Probamos RIAK, Cassandra, incluso una base de datos de gráficos. Todas estas son soluciones bastante específicas que no encajaban en el papel de una herramienta universal general para la creación de servicios.



Al final, nos decidimos por Tarantool.



Nos comunicamos con él cuando estaba en la versión 1.6. Nos interesaba por la simbiosis de clave-valor y la funcionalidad de una base de datos relacional. Hay índices secundarios, transacciones y espacios, son como tablas, pero no simples, puedes almacenar un número diferente de columnas en ellas. Pero las características principales de Tarantool fueron índices secundarios combinados con valor clave y transaccional.



La receptiva comunidad de habla rusa también jugó un papel, lista para ayudar en el chat. Usamos esto activamente y vivimos directamente en el chat. Y no se olvide de un persistente decente sin errores obvios y jambas. Si miras nuestra historia con Tarantool, tuvimos muchos dolores y fakups con la replicación, ¡pero nunca perdimos datos debido a su culpa!



La implementación comenzó con dificultad



En ese momento, nuestra pila de desarrollo principal era .NET, al que no había ningún conector para Tarantool. Inmediatamente comenzamos a hacer algo en Go. Lua también funcionó bastante bien. El principal problema en ese momento era la depuración: en .NET todo es magnífico con esto, y después de eso fue difícil sumergirse en el mundo de Lua embebido, cuando tú, además de los registros, no tienes depuración, fue difícil. Además, la replicación por alguna razón se desmoronaba periódicamente, así que tuve que ahondar en la estructura del motor Tarantool. El chat ayudó con esto, en menor medida: la documentación, a veces miraba el código. En ese momento, la documentación era regular.



Entonces, en unos meses, logré llenar los conos y obtener resultados decentes al trabajar con Tarantool. Formalizamos los desarrollos de referencia en git, lo que ayudó con la formación de nuevos microservicios. Por ejemplo, cuando surgió la tarea: crear otro microservicio, el desarrollador miró el código fuente de la solución de referencia en el repositorio y no tardó más de una semana en crear uno nuevo.



Eran tiempos especiales. De manera convencional, entonces era posible ir al administrador en la mesa de al lado y preguntar: "Dame una máquina virtual". Treinta minutos después ya tenías el auto. Usted mismo se conectó, instaló todo y obtuvo tráfico.



Hoy no funcionará así: necesitas terminar el monitoreo, iniciar sesión en el servicio, cubrir la funcionalidad con pruebas, pedir una máquina virtual o entregarla a Kuber, etc. En general, será mejor, aunque más largo y más problemático.



Divide y vencerás. ¿Y Lua?



Había un dilema serio: algunos equipos no podían implementar cambios de manera confiable en un servicio con mucha lógica de Lua. A menudo, esto iba acompañado de la inoperancia del servicio.



Es decir, los desarrolladores están preparando algún tipo de cambio. Tarantool inicia la migración y la réplica todavía tiene el código antiguo; algo de DDL, algo más, llega allí por replicación, y el código simplemente se desmorona, porque no se tiene en cuenta. Como resultado, el procedimiento de actualización para los administradores se programó en la hoja A4: detener la replicación, actualizarla, habilitar la replicación, apagarla aquí, actualizar allí. ¡Pesadilla!



Como resultado, ahora la mayoría de las veces tratamos de no hacer nada en Lua. Simplemente usando iproto (un protocolo binario para comunicarse con el servidor), y eso es todo. Quizás esto sea una falta de conocimiento entre los desarrolladores, pero desde este punto de vista, el sistema es complejo.



No siempre seguimos ciegamente este escenario. Hoy no tenemos blanco y negro: o todo está en Lua, o todo está en Go. Ya entendemos cómo puede combinarlos para que no tenga problemas con la migración más adelante.



¿Dónde está Tarantool ahora?

Tarantool se utiliza en el servicio para calcular el costo final de los bienes, teniendo en cuenta los cupones de descuento, también conocido como "Promotor". Como dije antes, ahora se retira: está siendo reemplazado por un nuevo servicio de catálogo con precios precalculados, pero hace seis meses, todos los cálculos se hicieron en el Promotor. Anteriormente, la mitad de su lógica estaba escrita en Lua. Hace dos años se hizo un almacenamiento desde el servicio, y se reescribió la lógica a Go, porque la mecánica de los descuentos cambió levemente y el servicio carecía de rendimiento.



Uno de los servicios más críticos es el perfil de usuario. Es decir, todos los usuarios de Wildberries están almacenados en Tarantool, y hay alrededor de 50 millones de ellos. Un sistema fragmentado por ID de usuario, distribuido en varios DC con una conexión a los servicios Go.

Según RPS, "Promotor" fue una vez líder, alcanzando 6 mil solicitudes. En un momento, teníamos entre 50 y 60 copias. Ahora el líder en RPS son los perfiles de usuario, alrededor de 12 000. Este servicio utiliza fragmentación personalizada con una división por rangos de ID de usuario. El servicio atiende a más de 20 máquinas, pero esto es demasiado, planeamos reducir los recursos asignados, porque la capacidad de 4-5 máquinas es suficiente para ello.



El servicio de sesión es nuestro primer servicio en vshard y Cartridge. Configurar vshard y actualizar Cartridge requirió algo de trabajo por nuestra parte, pero al final todo salió bien.



El servicio para mostrar diferentes banners en el sitio web y en la aplicación móvil fue uno de los primeros en lanzarse directamente en Tarantool. Este servicio se destaca por el hecho de que tiene entre 6 y 7 años, todavía está en servicio y nunca se ha reiniciado. La réplica fue maestro-maestro. Nunca rompí nada.



Hay un ejemplo del uso de Tarantool para la funcionalidad de referencia rápida en un sistema de almacén para verificar rápidamente la información en algunos casos. Intentamos usar Redis para esto, pero los datos en la memoria ocupaban más espacio que Tarantool.



Los servicios de lista de espera, suscripciones de clientes, historias de moda y productos almacenados también funcionan con Tarantool. El último servicio en memoria es de unos 120 GB. Este es el servicio más extenso de los anteriores.



Conclusión



Los índices secundarios combinados con las propiedades transaccionales y de valor clave hacen que Tarantool sea ideal para arquitecturas de microservicios. Sin embargo, tuvimos dificultades al implementar cambios en los servicios con mucha lógica en Lua; los servicios a menudo dejaban de funcionar. No pudimos vencer esto, y con el tiempo llegamos a diferentes combinaciones de Lua y Go: sabemos dónde usar un idioma y dónde usar otro.



Qué más leer sobre el tema






All Articles