Cómo escalar de 1 a 100,000 usuarios

Muchas startups pasaron por esto: las multitudes de nuevos usuarios se registran todos los días, y el equipo de desarrollo está luchando para apoyar el trabajo del servicio.

Este es un problema agradable, pero hay poca información clara en la Web sobre cómo escalar con precisión una aplicación web de cero a cientos de miles de usuarios. Por lo general, hay soluciones contra incendios o la eliminación de cuellos de botella (y, a menudo, ambos). Por lo tanto, las personas usan trucos bastante estereotipados para escalar su proyecto de aficionado en algo realmente serio.

Intentemos filtrar la información y anotar la fórmula principal. Vamos a escalar paso a paso nuestro nuevo sitio para compartir fotos Graminsta de 1 a 100,000 usuarios.

Anotaremos qué acciones específicas deben hacerse al aumentar la audiencia a 10, 100, 1000, 10 000 y 100 000 personas.

1 usuario: 1 automóvil


Casi todas las aplicaciones, ya sea un sitio web o una aplicación móvil, tienen tres componentes clave:

  • API
  • base de datos
  • cliente (aplicación móvil o sitio web en sí)

La base de datos almacena datos persistentes. La API atiende solicitudes para y alrededor de estos datos. El cliente transfiere los datos al usuario.

Llegué a la conclusión de que es mucho más fácil hablar sobre escalar una aplicación si, desde el punto de vista de la arquitectura, las entidades cliente y las API están completamente separadas.

Cuando comenzamos a crear una aplicación, los tres componentes se pueden ejecutar en el mismo servidor. En cierto modo, esto nos recuerda nuestro entorno de desarrollo: un ingeniero ejecuta la base de datos, la API y el cliente en la misma computadora.

Teóricamente, podríamos implementarlo en la nube en una instancia de DigitalOcean Droplet o AWS EC2, como se muestra a continuación:

Dicho esto, si el sitio tiene más de un usuario, casi siempre tiene sentido resaltar el nivel de la base de datos.

10 usuarios: llevar la base de datos a un nivel separado


Dividir una base de datos en servicios administrados como Amazon RDS o Digital Ocean Managed Database nos será de gran utilidad durante mucho tiempo. Esto es un poco más costoso que el autohospedaje en una sola máquina o una instancia EC2, pero con estos servicios obtendrá muchas extensiones útiles listas para usar que serán útiles en el futuro: copias de seguridad de varias regiones, réplicas de lectura, copias de seguridad automáticas y mucho más.

Así es como se ve el sistema ahora:

100 usuarios: llevando al cliente a un nivel separado


Afortunadamente, a nuestra aplicación realmente le gustaron los primeros usuarios. El tráfico se está volviendo más estable, por lo que es hora de mover al cliente a un nivel separado. Cabe señalar que la separación de entidades es un aspecto clave de la construcción de una aplicación escalable. Como una parte del sistema recibe más tráfico, podemos dividirlo para controlar la escala del servicio en función de patrones de tráfico específicos.

Es por eso que me gusta representar al cliente por separado de la API. Esto hace que sea muy fácil hablar sobre el desarrollo para varias plataformas: web, web móvil, iOS, Android, aplicaciones de escritorio, servicios de terceros, etc. Todos ellos son solo clientes que usan la misma API.

Por ejemplo, ahora nuestros usuarios solicitan con mayor frecuencia lanzar una aplicación móvil. La separación de entidades cliente y API lo hace más fácil.

Así es como se ve el sistema:



1000 usuarios: agregar balanceador de carga


Las cosas estan yendo bien. Los usuarios de Graminsta están subiendo más y más fotos. El número de registros también está creciendo. Nuestro único servidor API tiene dificultades para administrar todo el tráfico. ¡Necesito más hierro!

El equilibrador de carga es un concepto muy poderoso. La idea clave es que colocamos el equilibrador frente a la API, y distribuye el tráfico entre instancias de servicio individuales. Esta es la forma de escalado horizontal, es decir, agregamos más servidores con el mismo código, aumentando la cantidad de solicitudes que podemos procesar.

Vamos a colocar equilibradores de carga separados frente al cliente web y frente a la API. Esto significa que puede ejecutar varias instancias que ejecutan el código API y el código del cliente web. El equilibrador de carga reenviará las solicitudes a ese servidor que esté menos cargado.

Aquí obtenemos otra ventaja importante: la redundancia. Cuando una instancia falla (posiblemente se sobrecarga o se bloquea), todavía tenemos otras que aún responden a las solicitudes entrantes. Si una sola instancia funcionó, entonces, en caso de falla, todo el sistema se caería.

El equilibrador de carga también proporciona escalado automático. Podemos configurarlo para aumentar el número de instancias antes de la carga máxima y reducir cuando todos los usuarios duermen.

Con un equilibrador de carga, el nivel de API se puede escalar hasta el infinito, solo agregamos nuevas instancias a medida que aumenta el número de solicitudes.


. , PaaS, Heroku Elastic Beanstalk AWS ( ). Heroku , - API. , Heroku — .

10 000 : CDN


Quizás debería haberse hecho desde el principio. El procesamiento de solicitudes y la toma de nuevas fotos están comenzando a cargar demasiado nuestros servidores.

En esta etapa, debe utilizar un servicio en la nube para almacenar contenido estático: imágenes, videos y mucho más (AWS S3 o Digital Ocean Spaces). En general, nuestra API debe evitar procesar cosas como cargar imágenes y subir imágenes a un servidor.

Otra ventaja del alojamiento en la nube es su CDN (en AWS, este complemento se llama Cloudfront, pero muchos servicios de almacenamiento en la nube lo ofrecen de forma inmediata). CDN almacena automáticamente en caché nuestras imágenes en varios centros de datos de todo el mundo.

Aunque nuestro centro de datos principal puede estar ubicado en Ohio, pero si alguien solicita una imagen de Japón, el proveedor de la nube hará una copia y la guardará en su centro de datos japonés. La próxima persona que solicite esta imagen en Japón la recibirá mucho más rápido. Esto es importante cuando trabajamos con archivos grandes, como fotos o videos que tardan mucho tiempo en cargarse y transmitirse en todo el planeta.



100.000 usuarios: escala de nivel de datos


CDN realmente ayudó: el tráfico está creciendo a toda velocidad. La famosa video blogger, Maid Mobrick, acaba de registrarse con nosotros y publicó su historia, como dicen. Gracias al equilibrador de carga, el nivel de uso de CPU y memoria en los servidores API se mantiene bajo (se están ejecutando diez instancias API), pero estamos comenzando a tener muchos tiempos de espera para las solicitudes ... ¿de dónde provienen estos retrasos?

Después de investigar un poco las métricas, vemos que la CPU en el servidor de la base de datos tiene una carga del 80-90%. Estamos al limite.

Escalar la capa de datos es probablemente la parte más difícil de la ecuación. Los servidores API atienden solicitudes sin estado, por lo que solo agregamos más instancias API. Pero con la mayoríaLas bases de datos no tienen éxito. Discutiremos los populares sistemas de gestión de bases de datos relacionales (PostgreSQL, MySQL, etc.).

Almacenamiento en caché


Una de las formas más fáciles de aumentar el rendimiento de nuestra base de datos es introducir un nuevo componente: el nivel de caché. El método de almacenamiento en caché más común es almacenar registros de valores clave en la RAM, como Redis o Memcached. La mayoría de las nubes tienen una versión administrada de estos servicios: Elasticache en AWS y Memorystore en Google Cloud.

El caché es útil cuando un servicio realiza muchas llamadas repetidas a la base de datos para obtener la misma información. De hecho, accedemos a la base de datos solo una vez, guardamos la información en el caché y ya no la tocamos.

Por ejemplo, en nuestro servicio Graminsta, cada vez que alguien va a la página de perfil estrella de Mobric, el servidor API solicita información de su perfil en la base de datos. Sucede una y otra vez. Dado que la información del perfil de Mobrick no cambia con cada solicitud, es excelente para el almacenamiento en caché.

Almacenaremos en caché los resultados de la base de datos en Redis por clave user:idcon un período de validez de 30 segundos. Ahora, cuando alguien ingresa al perfil de Mobrick, primero verificamos Redis, y si los datos están allí, simplemente los transferimos directamente desde Redis. Ahora, las consultas al perfil más popular en el sitio prácticamente no cargan nuestra base de datos.

Otra ventaja de la mayoría de los servicios de almacenamiento en caché es que son más fáciles de escalar que los servidores de bases de datos. Redis tiene un modo de clúster Redis Cluster incorporado. Como un balanceador de carga1, le permite distribuir la memoria caché de Redis en varias máquinas (en miles de servidores, si es necesario).

Casi todas las aplicaciones a gran escala utilizan el almacenamiento en caché; esta es una parte absolutamente integral de la API rápida. Procesamiento de solicitudes más rápido y código más productivo: todo esto es importante, pero sin un caché es casi imposible escalar el servicio a millones de usuarios.

Leer réplicas


Cuando el número de consultas a la base de datos ha aumentado significativamente, podemos hacer una cosa más: agregar réplicas de lectura en el sistema de administración de la base de datos. Usando los servicios administrados descritos anteriormente, esto se puede hacer con un solo clic. La réplica de lectura seguirá siendo relevante en la base de datos principal y estará disponible para las instrucciones SELECT.

Aquí está nuestro sistema ahora:



Otras acciones


A medida que la aplicación continúe escalando, continuaremos separando los servicios para escalarlos de forma independiente. Por ejemplo, si comenzamos a usar Websockets, tiene sentido extraer el código de procesamiento de Websockets en un servicio separado. Podemos ubicarlo en nuevas instancias detrás de nuestro propio equilibrador de carga, que puede escalar hacia arriba y hacia abajo dependiendo de las conexiones abiertas de Websockets e independientemente de la cantidad de solicitudes HTTP.

También seguimos luchando contra las restricciones a nivel de base de datos. Es en esta etapa que ha llegado el momento de estudiar la partición y fragmentación de la base de datos. Ambos enfoques requieren una sobrecarga adicional, pero le permiten escalar la base de datos casi hasta el infinito.

También queremos instalar un servicio de monitoreo y análisis como New Relic o Datadog. Esto identificará consultas lentas y comprenderá dónde se necesita mejorar. A medida que escalamos, queremos centrarnos en encontrar cuellos de botella y resolverlos, a menudo utilizando algunas ideas de las secciones anteriores.

Fuentes


Esta publicación está inspirada en una de mis publicaciones favoritas de alta escalabilidad . Quería concretar un poco el artículo para las etapas iniciales de los proyectos y desvincularlo de un proveedor. Asegúrese de leer si está interesado en este tema.

Notas al pie


  1. A pesar de las similitudes en términos de equilibrio de carga en varias instancias, la implementación básica del clúster Redis es muy diferente del equilibrador de carga. [regresar]



Source: https://habr.com/ru/post/undefined/


All Articles