Escalado bajo demanda: Cómo Serverless maneja los picos de tráfico con facilidad

Escalado bajo demanda: Cómo Serverless maneja los picos de tráfico con facilidad

En el artículo anterior, discutimos dos modelos de proceso para Serverless: ejecución hasta completar y procesos de larga duración. La diferencia clave entre estos modelos radica en si la instancia de función termina inmediatamente después de la ejecución. Además, exploramos dos escenarios: orquestación de datos y orquestación de servicios.

Quizás te preguntes si estos escenarios se pueden implementar usando procesos de larga duración. La respuesta es sí, pero es importante señalar que la ejecución hasta completar es la forma más pura de Serverless. Entonces, ¿cuál es la lógica subyacente?

Para comprenderlo completamente, necesitamos introducir un concepto crucial en la evolución de la arquitectura de aplicaciones complejas de internet: el escalado, que es el enfoque de este artículo.

Imagina que 200 usuarios acceden simultáneamente a la página de inicio index.html de tu aplicación web desarrollada localmente. ¿Qué le sucede a tu instancia del servidor web local?

Describamos el estado de tu PC. En primer lugar, se establecen 200 conexiones TCP/IP entre los clientes y tu PC, algo que apenas puede manejar. Luego, los 200 clientes inician simultáneamente solicitudes HTTP “GET/”. El proceso principal de tu servidor web crea procesos secundarios de “número de núcleos de CPU - 1” de forma concurrente para manejar estas solicitudes. Ten en cuenta que restamos uno del recuento de núcleos de CPU para reservar uno para el proceso principal.

Por ejemplo, una CPU de 4 núcleos crea tres procesos secundarios para manejar tres solicitudes de clientes simultáneamente, mientras que las solicitudes restantes se ponen en cola. Los procesos secundarios comienzan a procesar las solicitudes “GET/”, coinciden con las reglas de enrutamiento, ingresan a la función de control correspondiente y devuelven index.html a los clientes. Una vez que un proceso secundario envía el archivo index.html, el proceso principal lo recicla y crea uno nuevo para manejar la siguiente solicitud hasta que se procesen todas.

Entendiendo esto, la siguiente pregunta se vuelve simple. ¿Cómo mejoramos la velocidad de procesamiento de nuestra cola de clientes?

Escalado vertical vs. Escalado horizontal

Una solución obvia es aumentar el número de núcleos de CPU. Podemos lograrlo actualizando la configuración de una sola máquina, por ejemplo, de 4 a 8 núcleos, lo que da como resultado 7 procesos secundarios concurrentes.

Además de aumentar directamente los núcleos de CPU, podemos agregar más máquinas (cada una con 4 núcleos). Al distribuir 500 clientes a cada una de las dos máquinas, también podemos aumentar el número de procesos secundarios concurrentes a 6.

Aumentar o disminuir el rendimiento de una sola máquina es escalado vertical, que a menudo conlleva una curva de costos pronunciada a medida que aumenta el rendimiento. Por lo tanto, se debe considerar cuidadosamente al adoptar este enfoque. Por otro lado, aumentar o disminuir el número de máquinas es escalado horizontal, un enfoque más rentable y nuestro método de escalado predeterminado.

Ahora, agreguemos algo de complejidad. Si bien index.html es un solo archivo, ¿qué pasa con los datos? Ya sea escalando vertical u horizontalmente, necesitamos reiniciar las máquinas. En nuestro ejemplo de lista de tareas, los datos se almacenan en la memoria y se reinician en cada reinicio. Entonces, ¿cómo preservamos nuestros datos durante el escalado?

Con estado vs. Sin estado

Los nodos en una topología de red se pueden clasificar como con estado o sin estado según si almacenan estado. Los nodos con estado retienen estado, lo que significa que almacenan datos. Por lo tanto, requieren atención adicional, exigiendo estabilidad y resistencia a cambios frecuentes. Por ejemplo, las bases de datos suelen emplear una estructura maestro-esclavo, lo que permite cambiar inmediatamente a un nodo esclavo si el nodo maestro presenta problemas, asegurando la disponibilidad continua del servicio.

Los nodos sin estado, por otro lado, no almacenan ningún estado o solo mantienen datos no confiables temporalmente. Debido a su falta de estado, los nodos sin estado se pueden escalar horizontalmente para manejar alta concurrencia y reducirse a cero cuando no hay tráfico (¿te suena familiar?). Los nodos con estado, sin embargo, no pueden hacer esto. En escenarios con fluctuaciones significativas de tráfico entre horas pico y valle, necesitamos diseñar nodos con estado para manejar el tráfico pico mientras mantenemos los costos operativos incluso durante períodos de bajo tráfico.

Una base de datos es un nodo típico con estado, ya que almacena permanentemente las tareas pendientes de los usuarios. Del mismo modo, un balanceador de carga también tiene estado, muy parecido al proceso principal que mantiene la cola de clientes en nuestro experimento mental. Necesita almacenar las conexiones de los clientes para poder devolver los resultados procesados por nuestra aplicación web a los clientes.

Volviendo a nuestros modelos de proceso, la ejecución hasta completar es inherentemente sin estado, ya que termina después de la ejecución, lo que hace imposible usarla sola para el almacenamiento persistente de datos. Los procesos de larga duración, sin embargo, son naturalmente con estado porque su proceso principal no sale, lo que le permite almacenar algunos valores.

Sin embargo, en Serverless, incluso si almacenamos valores en el proceso principal de un proceso de larga duración, el proveedor de la nube aún podría reclamarlo. Incluso con instancias reservadas, los datos en la memoria de los nodos escalados permanecen aislados.

Por lo tanto, para hacer que los procesos de larga duración sean sin estado, debemos evitar almacenar valores en el proceso principal o solo almacenar variables temporales. Los datos persistentes deben moverse a nodos dedicados con estado, como bases de datos.

Al separar el almacenamiento de datos del nodo del proceso principal y asegurarnos de que el proceso principal no retenga datos, nuestra aplicación se vuelve sin estado. Almacenamos los datos en un nodo de base de datos separado y con estado. Este ejemplo se transforma en el escenario de Serverless de larga duración discutido en el artículo anterior, donde nos conectamos a la base de datos durante el inicio del proceso principal y accedemos a los datos a través de procesos secundarios. Sin embargo, este enfoque tiene un inconveniente significativo: aumenta directamente el tiempo de inicio en frío. ¿Existe una mejor solución?

Consideremos un enfoque alternativo para la persistencia de datos. ¿Por qué tenemos que conectarnos nosotros mismos a la base de datos? Nuestras operaciones CRUD (crear, leer, actualizar, eliminar) sobre los datos esencialmente implican que los procesos secundarios reutilizan la conexión TCP establecida por el proceso principal, envían sentencias de base de datos y recuperan datos. Imagina si pudiéramos enviar instrucciones a la base de datos usando solicitudes HTTP como POST, DELETE, PUT y GET. ¿No nos permitiría eso aprovechar los conceptos de orquestación de datos y servicios de la lección anterior?

¿Qué es BaaS?

De hecho, todo este trabajo preparatorio nos lleva al protagonista de hoy: la BaaSificación. Las operaciones de interfaz de datos POST, DELETE, PUT y GET corresponden a los métodos HTTP semánticos de las API RESTful. Tomando MySQL como ejemplo, POST se asigna al comando CREATE, DELETE a DELETE, PUT a UPDATE y GET a SELECT. Esta correspondencia semántica uno a uno nos permite traducir naturalmente las operaciones de MySQL en operaciones de API RESTful.

Los enfoques tradicionales de base de datos, debido a la reutilización de conexiones TCP y la baja sobrecarga de comunicación, son más rápidos para las mismas operaciones en comparación con HTTP. Si bien Serverless puede conectarse directamente a bases de datos, conectarse a bases de datos tradicionales mediante direcciones IP a menudo resulta desafiante en entornos de nube con segmentación VPC. Por lo tanto, para las conexiones de Serverless a bases de datos, generalmente dependemos de servicios BaaS proporcionados por los proveedores de la nube, aunque muchos servicios BaaS aún no están maduros.

Llevándolo un paso más allá, si Serverless no es adecuado para nodos con estado, ¿por qué no externalizar todas las operaciones con estado como interfaces de datos? Esto permite que nuestras funciones Serverless utilicen el enfoque de orquestación de datos discutido en la lección anterior y logren un escalado libre.

Resumen

La razón por la que el modelo de ejecución hasta completar se considera más puro que el modelo de proceso de larga duración es porque este último puede ser engañoso, tentándonos a tratarlo como PaaS y usarlo como un nodo con estado para almacenamiento permanente de datos. Sin embargo, en Serverless, incluso con procesos de larga duración, los proveedores de la nube pueden reclamar nuestras instancias de función.

Al igual que en nuestro ejemplo donde almacenar datos en la memoria resultaba en reinicios en cada reinicio, al adoptar una mentalidad de orquestación de datos y transformar las operaciones de base de datos backend en interfaces de datos, podemos descargar el almacenamiento de datos en Serverless a aplicaciones backend e interactuar con ellas utilizando la orquestación de datos como se explicó en la lección anterior. Sin embargo, necesitamos ir más allá de simplemente crear interfaces de datos para aplicaciones backend. Necesitamos adoptar la BaaSificación, liberando a los ingenieros backend de las preocupaciones operativas del lado del servidor durante el desarrollo.

Para el escalado, podemos elegir entre escalado vertical y horizontal. El escalado vertical se centra en mejorar el rendimiento de una sola máquina, pero a menudo conlleva un aumento de costos pronunciado, lo que lo convierte en una elección cautelosa. El escalado horizontal implica aumentar el número de máquinas, ofreciendo una curva de costos más suave y sirviendo como nuestro método de escalado predeterminado.

Los nodos con estado almacenan datos, mientras que los nodos sin estado procesan datos sin retenerlos. Solo los nodos sin estado se pueden escalar libremente. Los nodos con estado, responsables de almacenar datos críticos, exigen un manejo cuidadoso. Si queremos que los nodos de nuestra topología de red se escalen libremente, necesitamos externalizar sus operaciones de datos a nodos dedicados con estado.

Cuando nuestras funciones Serverless acceden a nodos con estado, es preferible que estos nodos proporcionen interfaces de datos en lugar de depender únicamente de comandos de base de datos, ya que las conexiones a bases de datos introducen sobrecarga adicional para las funciones Serverless. Además, para simplificar el desarrollo para los ingenieros backend, debemos esforzarnos por lograr la BaaSificación de los nodos con estado. Profundizaremos en la BaaSificación en artículos posteriores.

Novita AI es la plataforma en la nube integral que impulsa tus ambiciones de IA. APIs integradas, serverless, instancias de GPU — las herramientas rentables que necesitas. Elimina la infraestructura, comienza gratis y haz realidad tu visión de IA.

Lectura recomendada

Desvelando la revolución: Explorando el mundo de la computación Serverless

Análisis Serverless, comenzando desde los modelos de datos