Sistemas distribuidos: cuándo debe construirlos y cómo escalarlos. Una guía paso a paso.

Siempre me sorprende la cantidad de desarrolladores jóvenes que sufren del síndrome del impostor cuando comenzaron a crear su producto.

Lo entiendo, hay muchos ejemplos alucinantes de empresas líderes con sistemas distribuidos increíblemente complejos que pueden abordar miles de millones de solicitudes , actualizar con gracia cientos de aplicaciones sin ningún tiempo de inactividad, recuperarse de un desastre en segundos, lanzar cada 60 minutos y tener una velocidad ligera tiempos de respuesta desde cualquier parte del mundo.

Estas expectativas pueden ser bastante abrumadoras cuando comienza su proyecto. Pero como muchos de ustedes ya saben, la mayoría de estas empresas han comenzado con un sistema viable mínimo y una pila de tecnología muy pobre . Hay una razón simple para eso: no lo necesitaban cuando comenzaron. Dedicar más tiempo a diseñar su sistema en lugar de codificar podría, de hecho, hacer que falle .

Este artículo es una guía paso a paso . Le mostraré cómo, en Visage, comenzamos con el sistema más pequeño y construimos un sistema distribuido escalable de alta disponibilidad básico. Este es un caso de estudio real para eliminar sus complejos si nunca ha tenido la oportunidad de hacerlo usted mismo.

Cuando llegué a Visage como CTO, era el único ingeniero. No sabía nada sobre la pila de tecnología, pero me uní porque realmente me gustaba la idea de poder reclutar sin reclutadores internos o un servicio de recursos humanos. Esta era la idea central detrás de Visage: crowdsourcing impulsado por una gran cantidad de reclutadores invisibles que trabajan juntos en sus roles con la ayuda de inteligencia artificial que buscarían el talento más adecuado para usted en cuestión de días. Luegote relacionas directamente con ellos, sin intermediarios.

La “ multitud ” en el crowdsourcing activó instantáneamente mi cerebro de ingeniería: va a haber mucha gente trabajando al mismo tiempo , esperando un buen desempeño de cualquier parte del mundo. Me gustó el desafío.

Pero en cuanto al sistema, las cosas iban mal , muy mal . Esto es lo que encontré cuando llegué:

  • Una instancia de Wordpress comprometida que ejecuta cientos de complementos defectuosos obsoletos, que se ejecuta en una máquina virtual en un servidor compartido
  • Buzones de correo comprometidos
  • Un montón de documentos y hojas de cálculo de Google.

Y esto es perfectamente normal. Una vez más, no había ningún miembro técnico en el equipo y esperaba algo como esto. Aún así, el equipo se había centrado en una oportunidad comercial e hizo que el producto pareciera que funcionaba mágicamente mientras hacía todo manualmente. (Fingir hasta que lo hagas). Y eso es lo realmente asombroso.

No es de extrañar que mi primera tarea fuera volver a crear la máquina virtual, reinstalar una versión actualizada de Wordpress, asegurarme de que todos cambien sus contraseñas, establecer una política de contraseñas y eliminar docenas de malware en las computadoras de la empresa ... pero pasemos a las consideraciones de sistemas.

De Wordpress a una aplicación web

Su primer enfoque cuando comienza a construir un producto debe ser la información . Los datos son lo que impulsa el valor de su empresa . Será lo que utilice todos los días para tomar decisiones y lo que muestre a sus inversores para demostrar su progreso .

Necesita darle sentido a sus datos, y recuperar sus datos de diferentes fuentes con diferentes formatos será una gran pérdida de tiempo . Wordpress puede ser una muy buena opción en muchos casos al ahorrar bastante tiempo de ingeniería, pero para sus necesidades, el equipo de Visage tuvo que instalar complementos sofisticados que ya no se mantenían. Como resultado, no teníamos control sobre el modelo de datos generado y los datos que no podían ajustarse al modelo estaban dispersos en docenas de documentos y hojas de cálculo.

Entonces, a menos que exista un producto que ya se ajuste al 90% de sus necesidades, piense en un modelo de datos ideal y diseñe e implemente un producto mínimo viable (MVP) que pueda contener todos sus datos.

Entonces piensa en API . Su aplicación debe tener una API, será fundamental cuando finalmente la venda. No escale inmediatamente, sino codifique teniendo en cuenta la escalabilidad. Haga que su API no tenga estado y sea tan RESTful como sea posible, ya que todos esperarán poder consultarla utilizando métodos HTTP estándar.

Elegimos NodeJS en nuestro caso, porque la mayor parte de nuestro código solo estaría procesando entradas y salidas. NodeJS no bloquea y viene con una biblioteca que es conveniente para diseñar API: ExpressJS .

Si necesita un sitio web orientado al cliente, tiene varias opciones. Primero puede crear una capa en su servidor de aplicaciones que generará sus páginas o puede construir una aplicación Javascript de una sola página que será servida por un servidor de alojamiento web estático.

En Visage, optamos por la segunda opción y decidimos crear una aplicación para usuarios y otra para administradores. Esto era simplemente porque tendríamos expectativas mucho más grandes para los usuarios de las que necesitábamos con los administradores, y queríamos mantener ambas bases de código simples (también, para consideraciones CORS más adelante). Así es como se veía nuestro sistema:

Delegue el almacenamiento de datos confidenciales desde el principio

A menos que sea fundamental para su negocio, no existe una buena razón para almacenar datos personales confidenciales en sus sistemas. La seguridad es un asunto complejo, y si está modificando su código todos los días hasta que encuentre el mercado de su producto adecuado, se romperá. Suponga que cualquier persona con malas intenciones podría violar su aplicación si realmente quisiera.

La clave aquí es no guardar ningún dato que sería una ganancia rápida para un hacker. Nadie roba a un banco que no tiene dinero . Si está diseñando un producto SaaS, probablemente necesite autenticación y pago en línea. Hay muchos terceros con los que puede integrarse que se ocuparán de eso de una manera mucho mejor de lo que podría.

Auth0, por ejemplo, es el tercero más conocido para manejar la autenticación. Stripe también es una buena opción para pagos en línea. Dedicarán todos sus recursos y los mejores equipos de ingeniería de seguridad del planeta para mantener sus datos seguros , o no tendrán un negocio.

Los servicios en la nube son tus mejores amigos

Entonces, en este punto, teníamos una forma de almacenar todos nuestros datos, autenticación, pago en línea y una aplicación web que los clientes podían usar junto con una API que podíamos vender a los socios para diferentes casos de uso. Nuestra base de usuarios estaba creciendo y se hizo obvio que querían poder acceder a la aplicación en cualquier momento. Así que era hora de pensar en la escalabilidad y la disponibilidad .

Confiábamos en un servidor, pero solo podía manejar un número limitado de solicitudes, y cambiar de servidor o lanzar una nueva versión significaría eliminar la aplicación durante el lanzamiento. Nuestras siguientes prioridades fueron: equilibrio de carga , escalado automático , registro , replicación y copias de seguridad automatizadas . Por supuesto, si usted es el único ingeniero de su empresa, tratar de abordar todos estos problemas por su cuenta sería una completa locura.

Afortunadamente, vivimos en una época en la que solo un ingeniero completo puede construir fácilmente un sistema de este tipo en un par de días utilizando servicios en la nube como Amazon Web Services , Google Cloud Services o Azure . Decidimos trasladar nuestros sistemas a AWS porque en ese momento era la solución más completa y teníamos 2 años de créditos gratuitos.

Es por eso que principalmente hablaré sobre las soluciones de AWS en esta publicación, pero hay servicios equivalentes en otras plataformas. Este es también el momento que elegimos para comenzar a ejecutar nuestros módulos en contenedores Docker por muchas otras razones diferentes que no se tratarán en esta publicación (puede consultar este artículo para obtener más información: //medium.freecodecamp.org/amazon -fargate-adiós-infraestructura-3b66c7e3e413).

La forma en que decida ejecutar sus aplicaciones realmente depende de su caso de uso, como la flexibilidad que necesita frente al tiempo que puede dedicar a administrar su infraestructura.

No hay una buena o mala respuesta.

Puede optar por contener todos sus módulos y usar un sistema de administración de contenedores como ECS / EKS en AWS o Kubernetes Engine en GCP. Si no es así y no quiere lidiar con cosas como el autoescalado y el equilibrio de carga usted mismo, puede usar Elastic Beanstalk o App Engine.

Si desea ir completamente sin servidor , también puede combinar el uso de funciones Lambda y API Gateway. Decidimos apostar por ECS. Implementamos 3 instancias en 3 zonas de disponibilidad, un equilibrador de carga , configuramos el escalado automático según el uso de la CPU, integramos todos los registros de nuestros contenedores con Cloudwatch y configuramos métricas para ver errores , llamadas externas y tiempo de respuesta de la API .

Para nuestra base de datos, usamos MongoDB, porque nuestro modelo es un buen ajuste para una base de datos NoSQL y por su alta consistencia. Decidimos aprovechar MongoDB Atlas e implementamos 3 réplicas para permitir una alta disponibilidad. Entre otros servicios, ofrece Atlas escala automática , automatizados copias de seguridad y le permite ir atrás en el tiempo sin problemas en caso de desastre.

También decidimos alojar todos nuestros archivos web estáticos en S3 y usamos Cloudfront como CDN para que nuestras aplicaciones JS puedan cargarse muy rápidamente en cualquier parte del mundo y ser atendidas tantas veces como se solicite. Cloudfare también es una buena opción y ofrece una protección DDOS lista para usar .

Por simplicidad, decidimos usar Route 53 como nuestro DNS usando sus servidores de nombres para todos nuestros dominios. Este es uno de mis servicios favoritos en AWS. Te hace la vida mucho más fácil. Cada vez que desee servir algo a través de un nombre de dominio, ya sea una instancia EC2 , una IP elástica , un equilibrador de carga , una distribución de Cloudfront o cualquier cosa real , privada o pública, le llevará minutos porque está muy bien integrado con todos los otros servicios.

Combine eso con el Administrador de certificados que le permite obtener certificados SSL (comodines incluidos) gratis en minutos e implementarlos en todos sus servidores marcando una casilla, y tendrá la forma más rápida y confiable de habilitar HTTPS en todos sus módulos. Adiós certificados SSL “Let's Encrypt” que tuve que renovar e instalar en mis servidores cada 3 meses aproximadamente.

Decidir sobre una estrategia de almacenamiento en caché

Todo el mundo odia la administración de caché, el almacenamiento en caché puede ocurrir en muchas capas diferentes y los problemas relacionados con la caché son difíciles de reproducir y una pesadilla de depurar.

Desafortunadamente, el rendimiento de los sistemas distribuidos depende en gran medida de una buena estrategia de almacenamiento en caché . Hay muchos buenos artículos sobre buenas estrategias de almacenamiento en caché, por lo que no entraré en muchos detalles. Solo sepa que si sus recursos de la Web estática son pesados, probablemente querrá aprovechar la caché del navegador de su usuario usando inteligentemente el encabezado de control de caché.

Si las páginas enfrentadas de su usuario se generan en los servidores de aplicaciones una y otra vez, use un proxy de almacenamiento en caché como Squid . Pero lo más importante es que existe una alta probabilidad de que realice las mismas solicitudes a su base de datos una y otra vez. Para reducir la carga de su base de datos y ahorrar en el tiempo de transferencia de datos, use un sistema de almacenamiento en caché de objetos de memoria como memcached para objetos que se utilizan con frecuencia y que rara vez se actualizan .

Comenzamos a considerar el uso de Memcached porque con frecuencia solicitábamos los mismos perfiles de candidatos y ofertas de trabajo una y otra vez. Implementarlo en una máquina optimizada para memoria aumentó el rendimiento de nuestra API en más de un 30% cuando promediamos todos los tiempos de respuesta de solicitudes en un día. Memcached también se distribuye, por lo que puede ejecutarse en diferentes servidores pero actuar como si fuera solo un gran espacio de memoria para almacenar sus objetos.

Ubicación, ubicación, ubicación

Ahora tenemos un sistema distribuido que no tiene un solo punto de falla (si considera AWS ELB y un Memcached distribuido ), y puede escalar automáticamente hacia arriba y hacia abajo. También utilizamos el almacenamiento en caché para minimizar las transferencias de datos de la red. Se ve bastante bien. En ese momento, probablemente desee auditar a sus terceros para ver si absorberán la carga tan bien como usted.

Pero aún así, algunos de nuestros usuarios se quejaban de que la aplicación era un poco más lenta para ellos, especialmente cuando cargaban archivos. De hecho, incluso si nuestros archivos web estáticos se almacenaron en caché en todo el mundo (cortesía de la CDN), todos nuestros servidores de aplicaciones se implementaron solo en el oeste de los EE. UU. Los usuarios de Asia oriental experimentaron mucha más latencia, especialmente para las transferencias de big data.

La solución fue fácil: implementar exactamente el mismo clúster de ECS en una nueva región de Asia junto con un nuevo equilibrador de carga, y confiar en Route 53 Geoproximity Routing para dirigir a los usuarios al equilibrador de carga "más cercano". MongoDB Atlas también le permite implementar sus réplicas en todas las regiones, por lo que no se requiere trabajo adicional.

Conclusión

Si bien el sistema distribuido que ve aquí se ha simplificado para esta publicación, examinamos las partes que es más probable que vea en muchas aplicaciones web modernas. Otros temas relacionados pero que no se tratan son la arquitectura de microservicios, el almacenamiento y el cifrado de archivos, la fragmentación de bases de datos, las tareas programadas, la computación paralela asincrónica ... ¡tal vez en la próxima publicación!

Mi punto principal es: no intente construir el sistema perfecto cuando comience su producto. La mayoría de sus elecciones de diseño dependerán de lo que haga su producto y quién lo esté usando. Solo sabrá que cuando llegue al mercado de productos se ajuste y comience a tener una buena visión general de su base de usuarios, y eso puede llevar meses, incluso años.

Concéntrese en averiguar qué necesitan las personas y trate de encontrar una solución a su problema, incluso si tiene muchos pasos manuales . Luego, piense en formas de automatizar , dedique su tiempo a codificar y destruir , y utilice a terceros cuando tenga sentido.

No escale, pero siempre piense, codifique y planifique el escalado. Construya su sistema paso a paso , no aborde los problemas de diseño del sistema basados ​​en características que aún no están maduras y, finalmente, siempre intente encontrar la mejor compensación entre el tiempo que dedicará y la ganancia en rendimiento, dinero y reducción. riesgo.

Si le gustó este artículo y lo encontró útil, presione el botón de aplaudir y sígame para obtener más artículos de arquitectura y desarrollo. ?