¿Puede alguien explicarme la escalabilidad en el desarrollo web en términos de un sistema de chat?

Una aplicación scalabale es capaz de soportar una amplia gama de usuarios sin comprometer la experiencia del usuario o incurrir en un costo irrazonable.

Como solicitó por ejemplo una aplicación de chat, le daré un ejemplo para un sistema de chat cliente-servidor basado en web / móvil, y otro ejemplo para un sistema de chat basado en escritorio que se beneficia enormemente (en términos de escala) de una arquitectura completamente diferente. .

Sistema de chat basado en web / móvil

El sistema web / móvil generalmente incluye servicios de front-end, un equilibrador de carga para enrutar las solicitudes de los usuarios al front-end disponible, servicios de back-end para computación y procesamiento de datos más pesados ​​y almacenamiento.

Las aplicaciones de front-end son típicamente sin estado (escalamiento sin estado mejor). Son responsables de manejar las solicitudes de los usuarios, mostrar la página web y extraer / enviar datos desde / hacia el back-end. El back-end está compuesto (o mejor dicho) por micro servicios pequeños, independientes y desacoplados, cada uno enfocado en hacer una pequeña tarea. En un sistema de chat, normalmente tendrá un servicio de presencia (responsable de mantener la ubicación y el estado de los usuarios), servicio de mensajería instantánea, servicio de lista de contactos, etc.

Cada servicio debe tener al menos dos instancias, idealmente implementadas en servidores / bastidores / DC separados, de modo que cada uno pueda ser disparado a la cabeza sin causar una interrupción.

Para el almacenamiento persistente, un almacenamiento NoSQL (docdb, mongodb, etc.) hará que la escala horizontal sea mucho más simple que un almacenamiento SQL (MySQL, MS-SQL). Entonces, a menos que su aplicación requiera un modelo de consistencia más fuerte, NoSQL probablemente sería una mejor opción.

Su implementación aumentará o disminuirá (con suerte automáticamente) horizontal y verticalmente, según los requisitos de escalabilidad y el costo. Por lo general, comenzará con la menor cantidad de servidores posible (mínimo dos para permitir la actualización sin tiempo de inactividad) y aumente la capacidad según sea necesario.

Sugiero seguir los siguientes pasos:

  1. Pruebe su sistema de carga con un número creciente de usuarios sintéticos
  2. Aumentar el tamaño de las instancias (agregar RAM / CPU)
  3. Optimice sus aplicaciones para asegurarse de que se amplíen con gracia.
  4. Agregar capacidad (servidores front-end / back-end)
  5. Optimice sus aplicaciones para asegurarse de que se escalen con gracia
  6. Optimice el acceso a su capa de almacenamiento, use el almacenamiento en caché para aumentar el rendimiento y reducir los costos
  7. Medir e iterar

Seguramente encontrará los errores interesantes solo después de que su aplicación se implemente en producción y sea utilizada por usuarios reales. Desea construir una buena tubería de telemetría y seguir prácticas como Canary Deployment & Test Flights (combinado con monitoreo activo / pasivo) para mitigar el impacto en sus usuarios y poder detectar y recuperarse de estos errores rápidamente (con suerte antes de que sus usuarios lo hagan). aviso). Su arquitectura de microservicios le permitirá hacerlo de manera mucho más eficiente (que una arquitectura monolítica), confíe en mí.

Sistema de chat de escritorio

La belleza de los sistemas de chat (de escritorio) es que pueden escalar indefinidamente sin costosos recursos centralizados mediante el uso de una arquitectura descentralizada de muelle a muelle.

La arquitectura P2P puede escalar utilizando la potencia de procesamiento y conexión en red de las máquinas de los usuarios finales , que crece en proporción directa a la base de usuarios. Si diez usuarios están usando el sistema, el sistema tiene diez recursos a su disposición, si millones de usuarios están usando el sistema, el sistema tiene un millón de recursos. Un sistema P2P no tiene reparos en utilizar las máquinas de los usuarios finales disponibles para ejecutar la lógica que beneficia a la red en su conjunto, no solo a la aplicación cliente que se ejecuta en la máquina.

Un sistema de chat descentralizado utilizaría las máquinas de los usuarios finales disponibles para enrutar mensajes entre clientes, tal vez también manteniendo un índice global al ejecutar aplicaciones interconectadas en máquinas cliente con recursos disponibles.

Skype es un gran ejemplo para una aplicación que fue capaz de escalar magníficamente para servir a decenas de millones de usuarios que utilizan una arquitectura inteligente de muelle a muelle (P2P), sin una inversión significativa en infraestructura.

Déjame contarte una historia de nuestra experiencia. En 2011, en QuickBlox estábamos implementando nuestro SDK de chat desarrollado recientemente para un cliente con una base de usuarios bastante activa capaz de generar cantidades considerables de tráfico.

El cliente tenía un equipo técnico experimentado que insistió en que hiciéramos algunas pruebas de carga contra 100,000 usuarios concurrentes. Ese número estaba más allá de lo que el cliente necesitaba entonces, supongo que se sugirió solo para estar seguro.

Entonces lo hicimos. No teníamos mucha experiencia con la emulación de alta carga antes, pero rápidamente encontramos una gran herramienta de prueba de carga llamada Tsung, que era ideal para probar servicios de mensajería basados ​​en XMPP.

Ejecutamos Tsung contra nuestro servidor de chat instalado en una de las pequeñas instancias de AWS EC2. Pasó las pruebas con gran éxito y descubrimos que incluso podíamos hacer usuarios concurrentes de 200k y 250k antes de que la CPU alcanzara el límite máximo. Enviamos los informes al cliente y seguimos con la configuración.

Poco después del lanzamiento a producción, los usuarios reales comenzaron a incorporarse en grandes cantidades y nuestro sistema ha fallado. El cliente informó que solo una parte de los usuarios podía usar el chat, mientras que otros seguían enviando correos electrónicos enojados al servicio de atención al cliente. Estábamos monitoreando el lanzamiento de cerca y también recibíamos comentarios de los usuarios, por lo que sabíamos que algo iba mal, pero no sabíamos por qué. Entonces, como contramedida rápida, realizamos una migración de emergencia a instancias EC2 más potentes: Small -> Large -> XLarge -> 2x XLarge.

Eso ayudó pero solo un poco, los problemas persistieron. La CPU de las instancias no se agotó al máximo, pero los procesos de memoria y MySQL se sobrecargaron. Lanzar más hardware al problema simplemente no ayudó.

Con bastante rapidez identificamos una ineficiencia en nuestro inicio de sesión de usuario y mecanismo de sesión que solucionamos. Eso ayudó y resolvió nuestro primer problema. Ahora que todos los usuarios podían iniciar sesión y chatear, pronto se activó el problema N2, que tenía que ver con las notificaciones push.

El lanzamiento del que estoy hablando se centró en las primeras aplicaciones móviles (iOS y Android), pero hoy en día las alertas de notificaciones automáticas también se vuelven más comunes en las aplicaciones web. De todos modos, el siguiente problema que enfrentamos fue que muchos usuarios simplemente no recibieron sus alertas de mensajes. Esto no era una misión crítica, ya que cuando los usuarios estaban en línea, todo estaba bien. Sin embargo, una vez que se desconectan, esperan recibir notificaciones de cualquier chat entrante similar al que se hace en Skype y otras aplicaciones de mensajería instantánea. Nuestro sistema se encargó de eso a través de nuestra API de notificaciones push y el servidor de chat XMPP enviaría automáticamente una notificación push si el indicador de presencia del destinatario está configurado como ‘fuera de línea’. El único problema es que nuestra cola de notificaciones push y los trabajadores de procesamiento simplemente no pudieron manejar una carga realmente alta.

El último problema tardó más en solucionarse y finalmente nos llevó a perder al cliente. Varios otros clientes se vieron afectados por nuestra arquitectura de notificaciones push poco escalable en los primeros días. En algún momento pensamos que solucionamos el problema, pero resurgió cuando más tarde enfrentamos niveles cada vez mayores de uso concurrente. Hemos pasado por una serie de re-arquitecturas pasando de Ruby on Rails a los trabajadores de colas C ++ y luego reemplazando el almacenamiento de colas MySQL con una base de datos noSQL y luego con Redis. Llevamos a cabo una serie de revisiones de arquitectura general para disminuir la fricción entre los servicios y reducir el almacenamiento interno y la carga de procesamiento de colas. Nuestro rendimiento para notificaciones push ha aumentado algo como esto:

2-3 pulsaciones por segundo -> 10 pulsaciones por segundo -> 100 pulsaciones por segundo -> 1000 pulsaciones por segundo …

En este momento, hemos pasado por una serie de crisis de escalabilidad seguidas de mejoras en la arquitectura. Entre otras cosas, elaboramos un conjunto adecuado de herramientas para pruebas de carga que tiene en cuenta nuestra infraestructura de servicios en su conjunto, y no solo el servidor XMPP. Nuestra plataforma ahora procesa miles de millones de mensajes de chat y llamadas de API de forma rutinaria, pero sigo experimentando una mezcla de dolor y diversión cuando recuerdo los primeros fracasos. Sin embargo, todavía estamos lejos de ser ideales y felicitamos a los ingenieros de Whatsapp y otras aplicaciones populares de mensajería instantánea para consumidores para construir sistemas que se ocupen de ESE nivel de tráfico.

Como resumen, supongo que mi respuesta podría resumirse en lo siguiente:

  1. Los sistemas de mensajería a menudo tienen que incluir múltiples servicios y el rendimiento de su sistema estará limitado por el rendimiento del servicio más lento.
  2. Mover su código ineficiente a instancias de hardware / EC2 más potentes no ayuda.
  3. Asegúrese de pasar suficiente tiempo trabajando en escenarios y herramientas de prueba de carga realistas que emulen las condiciones de la vida real para todos sus servicios (no solo el servidor de chat).

Para ilustrar el punto # 1 aquí está mi bosquejo rápido a continuación. Esto está demasiado simplificado, no muestra la infraestructura real detrás, también se omiten algunas llamadas de video, etc., por simplicidad. La idea aquí: aparte del servidor de chat, hay muchos otros servicios que necesita si envía mensajes. Cada uno de ellos es un posible cuello de botella.