Capítulo 4. Las fuerzas que hay detrás de Serverless

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

Este capítulo se centra principalmente en comprender los ingredientes que se han unido para que la tecnología sin servidor tenga éxito ahora y en el futuro. (No tengo una bola de cristal, pero parece probable que las ventajas estructurales de la tecnología sin servidor continúen hasta que alguien descubra una forma aún mejor de ayudar a los desarrolladores a crear aplicaciones escalables).

Tres fuerzas principales se han combinado para permitir que la tecnología sin servidor se convierta en un paradigma popular. En la actualidad, muchas organizaciones siguen teniendo grandes monolitos críticos para el negocio, e incluso aplicaciones mainframe son una parte fundamental de muchas industrias. En los próximos 20 años, espero ver cómo la tecnología sin servidor desempeña un papel más importante en muchas de estas aplicaciones existentes, conviviendo con los monolitos y mainframes existentes. Esto es genial: la mayoría de las tecnologías no sustituyen completamente a sus predecesoras, sino que ofrecen nuevas opciones que se adaptan mejor a las nuevas necesidades. Espero que la tecnología sin servidor se convierta en el paradigma dominante para las nuevas aplicaciones (incluidas las aplicaciones de código bajo y sin código) y que los tecnólogos inteligentes encuentren formas de que la tecnología sin servidor se integre con las pilas tecnológicas existentes. Los ratones y los elefantes convivirán, por así decirlo(Figura 4-1).

Figura 4-1. Sin servidor y el monolito

Los dos principales impulsores de la adopción sin servidor son los siguientes:

Menor freno a la innovación

Toda infraestructura tiene cierta fricción en su uso, pero la sin servidor reduce el desperdicio de energía en la ejecución del software.

Microfacturación

Centrarse en las unidades de trabajo permite establecer una relación más clara entre los costes del servicio y el valor entregado.

En la primera adopción de la tecnología sin servidor, estos beneficios pueden ser pequeños, pero cada nuevo componente sin servidor aumenta la rentabilidad de la aplicación en su conjunto. Una vez que los beneficios alcanzan un punto de inflexión, la tecnología sin servidor se convierte en el valor predeterminado de una organización, y las herramientas y la infraestructura empiezan a aprovechar estas capacidades de forma integrada. Veamos cómo funciona cada uno de estos impulsores y por qué aumenta el valor.

Velocidad máxima: Reducir la resistencia aerodinámica

La mayoría de los proyectos de servicios de comienzan con uno o un pequeño número de procesos de servidor principales, lo que se denomina modelo monolito de desarrollo. Con el tiempo, el monolito acumula cada vez más funcionalidad, hasta que es el trabajo combinado de veinte, cincuenta o incluso cientos de desarrolladores, una inversión total de cientos o miles de años de ingeniería (por no mencionar los años de gestor de productos, los años de pruebas, etc.). Con el tiempo, los monolitos llegan a un punto en el que son tan grandes y sofisticados que ninguna persona entiende toda la aplicación, y los cambios a gran escala se hacen muy difíciles. Incluso los pequeños cambios pueden requerir una cuidadosa planificación y consideración, y trabajar en el monolito se asemeja más a grandes proyectos de obras públicas que a un paseo por el parque.

Como reacción a esta tendencia a ralentizar la velocidad en los grandes proyectos, nació el modelo demicroservicios. Este modelo de favorece la separación de cada pieza de funcionalidad en un servicio independiente y su unión con una mezcla de invocaciones remotas explícitas o mensajes asíncronos. Al construir servicios más pequeños, es más difícil que un servicio enrede a otro en sus detalles de implementación, y resulta más sencillo razonar sobre el cambio de comportamiento de un servicio concreto manteniendo constantes los demás servicios. El tamaño exacto de cada microservicio es cuestión de gustos; lo fundamental es que los contratos entre microservicios se expresen mediante API claras que cambien lenta y cuidadosamente.1

Además de las propiedades antientropía de separar las implementaciones de servicios disjuntos, los microservicios permiten a los equipos de aplicación elegir el mejor conjunto de lenguajes y herramientas de implementación para cada trabajo. Por ejemplo, una base de datos de pedidos podría estar representada por un frontend Java y una base de datos Postgres de respaldo, mientras que un catálogo de productos podría implementarse en TypeScript con almacenamiento en MongoDB. Al separar cada microservicio en un proceso independiente, los equipos pueden elegir mejor las tecnologías que se ajustan al espacio del problema: Python para los problemas de IA, Java para la lógica de dominio compleja, JavaScript o TypeScript para la presentación y la interfaz de usuario, y Erlang para la mensajería paralela de alta disponibilidad.

Siguiendo esta tendencia, el modelo FaaS descompone cada microservicio en un conjunto de unidades aún más pequeñas: cada punto final de invocación o manejador de eventos se construye y despliega como su propia unidad de cálculo independiente. En este modelo, incluso dos métodos diferentes de la misma API no comparten el mismo proceso de cálculo y puede que ni siquiera estén implementados en el mismo lenguaje. Esta separación tiene algunas ventajas:

Los cambios en los componentes pueden enviarse independientemente

Dado que cada función es un servicio y un conjunto de procesos de servidor independientes, es posible actualizar una función sin afectar al resto del sistema (suponiendo que la "actualización" siga funcionando realmente). Esto significa que los rollouts (y rollbacks) tienen el radio de explosión más pequeño posible cuando las cosas van mal: mira qué fue lo último que cambiaste, y deshaz ese cambio para volver a funcionar. Es sorprendente la frecuencia con que un simple "deshacer" puede hacer que un sistema vuelva a funcionar. Las funciones hacen que deshacer sea lo más sencillo posible.

Las asignaciones de recursos pueden dimensionarse por método

Cuando pones un montón de operaciones relacionadas pero diferentes en el mismo proceso del servidor, tienes que planificar la combinación de esas operaciones en el peor de los casos. Puede que la operación Lista necesite asignar 50 MB de RAM para deserializar, formatear y ensamblar una respuesta, pero sólo necesite 0,1 segundos de CPU para hacer el cálculo. Mientras, la operación Predecir necesita 20 segundos de CPU para calcular una respuesta y almacena en caché un modelo compartido de 200 MB en memoria. Si quieres que cada servidor pueda gestionar 10 solicitudes, tienes que planificar 200 + 10 × 50 = 700 MB de RAM para poder gestionar 10 Listas, y asignar 10 CPU para gestionar 10 Predicciones. Nunca ocurrirán ambas cosas a la vez, pero tienes que planificar para el peor de los casos.

Si asignas funciones separadas para Listar y Predecir, el método Listar puede necesitar 500 MB de RAM para 10 peticiones (no necesitan cargar el modelo de predicción en absoluto), pero sólo 1 CPU. Mientras, el método Predecir necesita 200 MB de RAM y 10 CPU para cada instancia. Como estás separando los dos tipos de peticiones, puedes reducir el tamaño de las instancias de Predecir disminuyendo las peticiones en vuelo por instancia. Suponiendo que estés utilizando un modelo sin servidor y escalando automáticamente estos dos métodos, entonces una mezcla de 34 Listas y 23 Pronósticos requeriría 6 servidores en el modelo clásico, y 4 servidores de Listas y 5 de Pronósticos de tamaño medio en el modelo FaaS. Aunque FaaS esté ejecutando una instancia adicional, los recursos totales necesarios son entre un 60% y un 70% superiores en el modelo tradicional de microservicios. Los monolitos sufren esto aún más; la planificación de la capacidad de los monolitos puede ser una caja cerrada sustancial dependiendo del grado de interacción entre los componentes.La Tabla 4-1 puede ayudar a visualizar estos dos escenarios.

Tabla 4-1. Ajuste de instancias para 34 peticiones de Listar y 23 de Predecir
Componente Métodos CPU en el peor de los casos Memoria del peor caso Instancias Recursos

Instancia compartida

Listar y Predecir, 10 peticiones simultáneas

10 × 1,0 (Predecir)

200 MB (modelo) + 10 × 50 MB (Lista)

6

10 CPU, 700 MB RAM por instancia

Total

6

100 CPUs, 7 GB RAM

Lista de instancias

Lista, 10 solicitudes simultáneas

10 × 0.1

10 × 50 MB

4

1 CPU, 500 MB RAM por instancia

Predecir instancias

Predecir, 5 peticiones simultáneas

5 × 1.0

200 MB

5

5 CPUs, 200 MB RAM por instancia

Total

9

29 CPUs, 3000 MB RAM

Dadas estas ventajas evidentes, ¿por qué los microservicios y la FaaS no son aún más populares de lo que son hoy? Como habrás adivinado por el título de esta sección, una fuerza opuesta impulsa a los equipos hacia los monolitos:la fricción. A pesar de todas las ventajas de implementar microservicios en lugar de monolitos, uno de los principales inconvenientes de los microservicios es la proliferación de pequeños servicios, como en la Figura 4-2. Cada servicio requiere cuidados y alimentación. ¿No sería más fácil alimentar y cuidar a un gran hipopótamo que a cientos de pequeños hámsters que necesitan citas separadas con el veterinario?

Figura 4-2. Tamaño del código y esfuerzo de mantenimiento

Esta fricción tiene muchas fuentes; algunas son intrínsecas a los servicios en vivo, y otras vienen impuestas por diversos procesos organizativos. Los costes intrínsecos son cosas como escribir las configuraciones de la aplicación, el monitoreo del tiempo de actividad, el mantenimiento de la compatibilidad de la API y la creación de artefactos. Los costes externos de los procesos organizativos son las revisiones de lanzamiento, las pruebas de aceptación dela aplicación o las auditorías de cumplimiento. Los costes externos no son necesariamente malos:son herramientas para alcanzar objetivos empresariales que no requiere la tecnología subyacente. La tecnología sin servidor puede ayudar a reducir los costes intrínsecos de ejecutar una aplicación simplificando la configuración y automatizando el monitoreo. Herramientas como la entrega continua pueden ayudar a reducir tanto los costes intrínsecos como los externos, simplificando los procesos de creación, prueba e incluso auditoría.

Cada equipo hace estas concesiones cada vez que estudia la posibilidad de añadir una nueva función o capacidad: si debe vivir dentro de una unidad de entrega existente, como un microservicio, o vivir en su propia unidad, añadiendo un nuevo caso de coste de "gestión de un servicio" a la carga que paga el equipo. (Recuerda que el equipo tiene una serie de cargas continuas, como "mantener las pruebas unitarias en verde" y "comunicarse con las partes interesadas". Añadir "mantener 273 microservicios" a esa carga contribuye a la fatiga y el agotamiento). Al reducir el coste de "mantener un servicio", resulta más fácil para un equipo desplazarse a la derecha a lo largo del espectro de laFigura 4-2 hacia unidades más pequeñas de entrega.

Aportar valor continuamente

Así, los microservicios pueden ser más fáciles de ejecutar y mantener, y facilitan el cambio de un componente sin consecuencias en cascada. A cambio, requieren más disciplina a la hora de hacer cambios que atraviesen microservicios. Pero, ¿por qué hablamos aquí de microservicios? ¿Necesito adoptar serverless para ejecutar microservicios?

No necesitas un servidor sin servidor para ejecutar microservicios, y no necesitas microservicios para ejecutar un servidor sin servidor. Pero los dos van juntos como la mantequilla de cacahuete y la mermelada (o como sea que se rellenen tus dos sándwiches favoritos). De aquí en adelante, generalmente asumiremos que has elegido ejecutar tus microservicios sin servidor para aprovechar las ventajas operativas descritas enel Capítulo 1, así como las ventajas que describiré a continuación.

En general, los microservicios facilitan la implementación de una serie de prácticas modernas de implementación, como la separación de datos, la entrega progresiva y la entrega continua. Los microservicios facilitan el cambio de las prácticas de implementación para cada pequeña pieza del rompecabezas de la entrega, sin necesidad de coordinarse entre varios puñados de equipos y docenas de personas. Estas mejoras se basan unas en otras, con la separación de datos y la entrega progresiva, cada una de las cuales proporciona capacidades hacia el objetivo final de la entrega continua:

Separación de datos

Los microservicios bien arquitecturados interactúan entre sí mediante API explícitas, ya sean RPC directas o mediante mensajería asíncrona. Esto permite a cada microservicio gestionar su propio almacén de datos mediante las abstracciones elegidas por el equipo. Por ejemplo, un equipo responsable de gestionar los carritos de la compra en una tienda online podría exponer una API en términos de pedidos y partidas. El sistema de pago podría exponer una API separada que consumiera pedidos e instrumentos de pago para ejecutar una transacción.

Dejar que los equipos elijan las abstracciones que exponen a otros equipos les permite definir interfaces en términos de conceptos de dominio empresarial, en lugar de tablas y relaciones. Ocultar la implementación de esas abstracciones detrás de una API permite al equipo del microservicio cambiar las opciones de almacenamiento e implementación detrás del microservicio sin afectar a otros equipos. Esto podría significar añadir una caché a una API de consulta existente o migrar de una base de datos relacional de instancia única a una base de datos NoSQL escalable para hacer frente a una mayor demanda de almacenamiento y E/S.

La separación de datos permite las siguientes prácticas; sin separación de datos, los cambios en la aplicación se acoplan entre microservicios, lo que dificulta la implementación de la entrega progresiva o continua.

Entrega progresiva

Una vez que los equipos son capaces de entregar cambios a su implementación de microservicios sin afectar a las API que utilizan para coordinarse con otros servicios, su siguiente reto es hacer que esa entrega de aplicaciones sea segura y repetible. La entrega progresiva es una técnica para aplicar cambios en pasos más pequeños y seguros. En lugar de desplegar todo el microservicio a la vez, se dirige un subconjunto de peticiones a la nueva versión, con la posibilidad de evaluar el rendimiento y la estabilidad de la nueva versión antes de enviar la mayor parte del tráfico de la aplicación a la nueva versión. Las Implementaciones azul-verde y canaria son ejemplos populares de entrega progresiva, pero esto también puede manifestarse como duplicación de tráfico o "lanzamiento oscuro" de nuevas rutas de código, donde se invocan tanto los servicios nuevos como los antiguos.

El objetivo de la entrega progresiva es hacer que la entrega de software sea más segura, reduciendo el impacto de los malos cambios y reduciendo el tiempo de recuperación cuando se produce un mal cambio. Como regla general, el daño global de una interrupción es el producto del radio de explosión (el número de usuarios afectados) por la duración de la interrupción. La entrega progresiva pretende reducir el daño de un mal despliegue, haciendo más seguro y rápido el despliegue de software.

Entrega continua

Cuando los equipos son capaces de desplegar los cambios de forma independiente y de reducir el impacto de los cambios de configuración erróneos, pueden empezar a implantar la entrega continua. Se han escrito libros enteros sobre este tema, pero a grandes rasgos, la entrega continua es la práctica de automatizar la entrega de software de forma que se pueda entregar software de forma segura con frecuencia -diaria o incluso con cada cambio de código en un repositorio-. Implementar la entrega continua a menudo significa automatizar todos los aspectos del ciclo de creación y publicación del software y conectar el mecanismo de entrega automatizada con el monitoreo de la aplicación, de modo que una publicación incorrecta pueda detectarse y revertirse automáticamente.

Ya hemos hablado de cómo el serverless puede simplificar la gestión de aplicaciones y las operaciones continuas, pero a menudo el serverless también tiene ventajas para alcanzar el nirvana de la entrega continua.

Consejo

La entrega continua no consiste en no tener nunca una interrupción o un fallo en el despliegue de software. El objetivo es reducir el riesgo de desplegar software reduciendo el daño potencial de un despliegue individual. Los lanzamientos pequeños y rápidos reducen la presión de combinar parches que deben corregirse con grandes novedades. Dividir el alcance de la implantación reduce el riesgo de que falle todo a la vez. La automatización reduce el riesgo de fallos debidos a variaciones del proceso.

Aunque la tecnología sin servidor no requiere separación de datos (y un microservicio podría implementarse en realidad como varios procesos coordinados sin servidor que comparten una base de datos común), la superficie de la API proporcionada a través de llamadas RPC directas o mensajería asíncrona se presta bien al modelo de unidad de trabajo sin servidor. Al motivar a los equipos para que definan API que puedan impulsar métricas de escalado sin servidor, los equipos también acaban implementando API escalables frente a las fuentes de datos de sus aplicaciones, y se hace más fácil definir subconjuntos de la aplicación que interactúan con una fuente de datos determinada y necesitan ser empujados juntos.

La entrega progresiva suele estar directamente soportada por el tiempo de ejecución sin servidor; como el tiempo de ejecución sin servidor ya conoce las unidades de trabajo, a menudo se incorporan mecanismos en el marco que permiten dividir o encaminar esas unidades a versiones específicas de la aplicación. Por ejemplo, Knative y muchas ofertas de FaaS ofrecen la opción de dividir el tráfico entre revisiones de la aplicación que el tiempo de ejecución rastrea automáticamente en la implementación.

Como colofón a la aceleración de la implementación de aplicaciones, las plataformas sin servidor pueden ayudar en la entrega continua porque están bien situadas para realizar un seguimiento de las métricas de aplicación de alto nivel a nivel de unidad de trabajo. La latencia, el rendimiento y la tasa de errores deberían ser accesibles a la automatización de la implementación basada en la integración con la pila de monitoreo de la plataforma. Obviamente, algunas métricas de implementación (como el número de pedidos realizados con éxito en el carrito de la compra) pueden no estar disponibles para la maquinaria de implementación sin métricas a nivel de aplicación, pero el monitoreo genérico de la unidad de trabajo puede proporcionar una envolvente básica de rendimiento adecuada para muchos equipos. Hablaré más sobre las capacidades de monitoreo de las plataformas sin servidor en el Capítulo 10.

Ganar la carrera (empresarial)

Es divertido para empujar código y que aparezca en vivo en el sitio de producción en 30 o 60 minutos, pero el beneficio real de la entrega continua es eliminar los límites tecnológicos en el tiempo de reacción de la organización. Al proporcionar un andamiaje de apoyo para implementar la entrega continua, las organizaciones que implementan un modelo de desarrollo serverless-first pueden reaccionar más rápidamente a los cambios en las necesidades de los clientes y experimentar de forma más ágil que las organizaciones que necesitan atender a un monolito.

En resumen, las organizaciones se benefician de dos maneras al adoptar una arquitectura de microservicios sin servidor:

Reducción del trabajo operativo

Históricamente, la principal ventaja de los monolitos era que un único equipo de operaciones podía especializarse y centrarse en construir una plataforma de ejecución que gestionara todas las aplicaciones en uno o una flota fija de servidores (piensa en servidores de aplicaciones cgi-bin o J2EE cargando docenas de microaplicaciones en un único servidor). Los microservicios implican mantener docenas de servidores, cada uno con una sola aplicación, lo que conlleva una mayor carga operativa, ya que cada servidor es único para la aplicación instalada. Simplificando las operaciones de las aplicaciones y automatizando algunas de las tareas comunes de monitoreo cotidiano, puede evitarse gran parte del trabajo de una arquitectura de microservicios.

Andamiaje para la entrega continua

Si la reducción del trabajo es la coraza aerodinámica de las aplicaciones, la entrega continua es el turbocompresor. La reducción del tiempo de cambio es una de las métricas clave utilizadas porDevOps Research and Assessment para identificar a las organizaciones de élite en la ejecución de software. Con el software abriéndose paso en cada vez más aspectos del negocio, la entrega continua permite un tiempo de reacción más rápido ante los acontecimientos inciertos del mundo. Reforzar el bucle observar-decidir-actuar ayuda a las organizaciones a seguir el ritmo de lo que el mundo les depare .

Esperemos que estos argumentos expliquen cómo la tecnología sin servidor puede ayudar a las organizaciones a tomar decisiones mejores y más rápidas. La siguiente sección explica cómo la tecnología sin servidor puede ayudar a las organizaciones a tomar decisiones más inteligentes.

Microfacturación

La sección anterior de hablaba de dividir las aplicaciones monolíticas en microservicios desde el punto de vista de la entrega de aplicaciones y la comodidad de los equipos de desarrollo. Estamos a punto de hablar de algo que puede incomodar mucho alos equipos de desarrollo, pero que puede arrojar una luz fascinante sobre la situación económica de una organización: el coste de la entrega de bienes y servicios (también conocido como coste de los bienes vendidos, o COGS para todos los que os dediquéis a los negocios).

Puede que a algunos os sorprenda saber que muchas empresas no comprenden sus costes informáticos. Los demás estaréis asintiendo y diciendo: "Evan, ve al grano". Al dividir los monolitos en microservicios y hacer un seguimiento de las unidades de trabajo, es posible asignar costes informáticos a líneas de negocio individuales, ¡a veces hasta el nivel de transacción!

Aunque los costes pueden medirse a un nivel muy preciso, el rendimiento de la inversión (ROI) puede ser mucho más difícil de calcular. Por ejemplo, los programas de fidelización de clientes pueden tener un coste fácilmente mensurable, pero una contribución difícil de medir a la fidelidad del cliente y a la repetición de las ventas.

Al desglosar los costes de forma detallada, resulta más fácil comprender qué servicios generan beneficios e ingresos. Si cuesta 0,50 $ captar a un usuario mediante una aplicación de chat de texto, por ejemplo, puedes comparar ese coste con el de contratar a un operador humano a 15 $/hora para responder a preguntas de texto; si el humano puede responder a más de 30 clientes por hora, en realidad es más barato que la aplicación, sin tener en cuenta los costes de formación y de desarrollo de la aplicación. Además, tal vez puedas centrarte en un componente concreto de IA que contribuya con 0,30 $ al precio de la interacción y optimizarlo, ya sea trasladándolo de la CPU a la GPU o viceversa, o cambiando el propio modelo para optimizar los costes.

Un trato con la nube

Facturar por hasta la unidad individual de trabajo es más sencillo con las plataformas sin servidor proporcionadas por la nube, que a menudo facturan directamente por el trabajo realizado, a veces hasta el milisegundo de CPU o RAM. Con las ofertas sin servidor proporcionadas por la nube, el proveedor de la nube es responsable de aprovisionar capacidad suficiente y gestionar la capacidad adicional no utilizada. A su vez, el proveedor de la nube captura parte del valor adicional de tener la ilusión de una capacidad infinita. Algunos estudios han sugerido que la computación sin servidor es aproximadamente cuatro veces más cara que las instancias IaaS estándar como Amazon Elastic Compute Cloud (EC2) (que, a su vez, tienen un coste superior al de las instalaciones locales). Aunque los proveedores de la nube pueden cambiar sus precios, y de hecho lo hacen, es probable que el valor aportado por la computación sin servidor siga haciendo que las ofertas sin servidor sean más caras por capacidad que las infraestructuras menos flexibles.

Dado que los proveedores de la nube suelen cobrar en función de las unidades de trabajo realizadas (es decir, ejecuciones de funciones) o del tiempo de ocupación de la CPU o la memoria mientras procesan las solicitudes, es fácil asignar los costes de un microservicio concreto a las personas que llaman a ese servicio y hacia arriba a las pilas de aplicaciones relacionadas. Es posible aprovechar el escalado a cero para desplegar varias copias de un microservicio, una para cada solicitud, pero esto suele ser innecesario porque es fácil determinar un coste por solicitud a partir de los precios del proveedor de la nube.

Aunque la asignación de cargos por solicitud al uso de la aplicación funciona bastante bien para aplicaciones de un solo hilo con una solicitud en vuelo por instancia, la facturación puede complicarse algo más con plataformas como Cloud Run (o Knative) de Google, donde una instancia puede procesar varias solicitudes a la vez. La principal ventaja del modelo de ejecución más complejo que ofrecen Cloud Run o Knative es que muchas aplicaciones sin servidor acaban gastando una cantidad considerable de tiempo de muro esperando respuestas de la API o del servicio. Dado que el tiempo de espera se utiliza a menudo como métrica de facturación tanto para la ocupación de memoria como de CPU, esto puede hacer que el multihilo y la gestión de múltiples solicitudes en una sola instancia sea una capacidad atractiva, aunque dificulte un poco la facturación. El aumento de eficiencia que supone habilitar la multiplexación de peticiones puede verse en la Figura 4-3, donde una instancia de tamaño doble puede ser capaz de gestionar cuatro veces más unidades de trabajo, ¡lo que supondría un ahorro de costes del 50%!

Figura 4-3. Gestión de múltiples solicitudes por instancia

Incluso si utilizas un modelo multihilo más complejo como Knative, promediar los costes de todas las solicitudes suele funcionar bien, a menos que combines solicitudes con perfiles de ejecución muy diferentes en un microservicio. Un ejemplo común son las peticiones a Get frente a List: normalmente, las primeras leen una única fila de la base de datos, mientras que las segundas pueden leer miles de filas de la base de datos, posiblemente filtrando los resultados o marshaleando grandes cantidades de datos. Separar Get y List en diferentes funciones o microservicios puede reducir la contención entre ambos, pero también puede contribuir a la complejidad operativa por un valor limitado, así que haz pruebas antes de aplicar ciegamente este consejo.

Una última advertencia: el uso de servicios sin servidor puede tener costes ocultos que son más difíciles de tener en cuenta a la hora de determinar los costes de las solicitudes. He aquí algunos ejemplos:

Salida de la red

Casi todos los proveedores de la nube cobran por separado los bytes de red enviados. Con suerte, tu plataforma sin servidor puede informar de la fracción del total de bytes enviados que se deben a tus aplicaciones sin servidor, pero contabilizar todo este tráfico a veces puede resultar difícil.

Sistemas de datos

Aunque unos pocos sistemas de bases de datos pueden llamarse realmente "sin servidor", la mayoría siguen estando vinculados a un conjunto bastante fijo de servidores o a una topología primario/réplica. Dado que los sistemas sin servidor suelen externalizar su almacenamiento, los servicios de datos pueden ser un coste oculto de los sistemas sin servidor difícil de contabilizar en tu coste de bienes y servicios.

Servicios multinivel

Cuando una aplicación se descompone en varias capas de software, se requiere trabajo adicional para comprender cómo deben atribuirse los costes del backend en función de las operaciones del frontend. Si todos los sistemas son sin servidor, el rastreo distribuido (ver "Rastreo") puede proporcionar el mapeo de los costes del frontend al backend. Si los backends no son sin servidor, los costes de pueden volverse opacos del mismo modo que los servicios de datos.

Enturbiamiento por tu cuenta

Hay muchas buenas razones por las que podrías optar por construir una plataforma sin servidor por tu cuenta en lugar de confiar en la oferta de un proveedor en la nube: las inversiones existentes o la sensibilidad a los costes, la falta de capacidades en la nube (por ejemplo, compatibilidad con GPU o integraciones de funciones específicas), los requisitos de computación de perímetro y físicos o normativos, o el deseo de disponer de herramientas coherentes en diferentes nubes son buenas razones. ¿Significa esto que tienes que abandonar el sueño de los modelos de costes sin servidor y comprender tu coste de prestación de servicios? Obviamente, no.

Si los proveedores de la nube pueden hacerlo, no es magia. Como mucho, es un poco complicado, pero es posible construir tu propio modelo de costes para la computación: herramientas como Kubecost permiten a las plataformas Kubernetes calcular los costes basándose en métricas y en la economía de la nube en torno a las máquinas virtuales, las redes y el almacenamiento. Con estas plataformas, puedes utilizar la información de monitoreo para determinar los recursos utilizados por cada pod, sumarlos por componente (tanto en los servicios sin servidor como en los más servidores), y luego asignar esos costes a grupos individuales.

También es posible hacer que estas herramientas amorticen (compartan) los costes de la plataforma subyacente: los equilibradores de carga, los agentes de nodo, el monitoreo, la recopilación de registros, etc., todos tienen un coste que normalmente se ejecuta de forma multiusuario en beneficio de todos los usuarios. Estos costes pueden dividirse mediante muchas políticas: coste igual por aplicación, coste igual por minuto de cálculo utilizado, o coste por segundo de cálculo reservado/provisto, son enfoques razonables que se han utilizado en la práctica.

Contabilizar la capacidad aprovisionada pero no utilizada puede ser complicado en este mundo; las máquinas físicas o virtuales que están encendidas pero no están ejecutando código de aplicación pueden ser prorrateadas como costes de plataforma de apoyo o aceptadas por la organización como "líder de pérdidas" para atraer clientes internos a la plataforma. En algunos casos, las organizaciones pueden recuperar parte o gran parte de este coste sobreaprovisionando (vendiendo los mismos núcleos o memoria dos veces, asumiendo algunas ineficiencias conocidas) o con el trabajo oportunista que se describe en el siguiente apartado.

Qué ocurre cuando no corres

Hasta ahora, hemos hablado de cómo funciona el serverless para ejecutar tu aplicación, pero no hemos hablado mucho de lo que ocurre con los servidores cuando no hay trabajo de aplicación que hacer. Una opción es simplemente permitir que los procesadores entren en estados de bajo consumo; esto puede ahorrar cientos de vatios de energía en los procesadores x86 recientes. El hardware sigue ahí sentado, y otros componentes como la RAM, el disco y las tarjetas complementarias también consumen cantidades no triviales de energía, generando calor y carga en los sistemas del centro de datos, como la refrigeración, las redes y la distribución de energía. Realmente parece que deberíamos poder hacer algo mejor con esa capacidad. (Y no, ¡no estoy hablando de minar Bitcoin!)

Como sugerí en la sección anterior, un uso para esta capacidad de base es la informática oportunista. Los sistemas como Kubernetes permiten programar el trabajo con distintos niveles de prioridad; las CPU que están ociosas con tareas de alta prioridad pueden asignar fragmentos de tiempo al trabajo de baja prioridad, al tiempo que están preparadas para pausar ese trabajo cuando llegue una nueva tarea de alta prioridad.

Según tu comodidad operativa, puedes aprovechar esta capacidad ociosa de varias maneras:

Cálculo por lotes

Muchas organizaciones de recopilan grandes cantidades de datos para su posterior análisis; a menudo, este análisis se necesita "al día siguiente laborable" o con limitaciones de tiempo similares. Al ejecutar este trabajo con menor prioridad en los mismos recursos consumidos por el trabajo sin servidor, el trabajo por lotes puede completarse en momentos en que la demanda de trabajo interactivo en tiempo real es menor. Las cargas de trabajo por lotes suelen ser también sin servidor: "mapear todos estos registros" o "reducir todas estas combinaciones" se escalan por unidades de trabajo. Este patrón funciona bien para problemas vergonzosamente paralelos, pero puede acabar siendo muy ineficiente para cargas de trabajo por lotes que requieren que cada trabajador se conecte directamente a otros trabajadores. Si estas conexiones directas se atascan debido a que el remitente o el destino pierden recursos en un proceso sin servidor, pueden producirse atascos en cascada de cientos de tareas.

Construir servicios

Las compilaciones de software son otra oportunidad para paralelizar el trabajo y mejorar la velocidad de desarrollo. Esto también puede extenderse a otros procesos de cálculo intensivo, como el renderizado 3D o el entrenamiento de modelos de IA. En lugar de aprovisionar ordenadores portátiles caros y que los ventiladores se pongan en marcha y las videoconferencias tartamudeen, los usuarios pueden descargar estas tareas de su máquina local a la capacidad sobrante disponible temporalmente entre picos de uso. Este modelo funciona mejor para grandes construcciones o renderizaciones que pueden llevar de decenas de minutos a horas de tiempo; rara vez merece la pena descargar en la nube todo el estado de una construcción de un minuto.

Desarrollo e investigación

Con suficiente capacidad sobrante y un fuerte aislamiento de las tareas sin servidor, una organización puede decidir permitir que los equipos de desarrollo utilicen la capacidad ociosa de baja prioridad para entornos de desarrollo o proyectos de investigación favoritos. Esto puede servir tanto de ventaja para los equipos de desarrollo como de oportunidad para la innovación dentro de la organización.

La fuerza gravitatoria de la ausencia de servidor

Espero haberte convencido en de que el desarrollo sin servidor ha llegado para quedarse y no es una moda pasajera. Además, las convincentes ventajas del desarrollo sin servidor harán que éste gane una cuota de mercado cada vez mayor, del mismo modo que los miniordenadores, las aplicaciones de escritorio, los servicios web, las API y los teléfonos móviles han aumentado su cuota de mercado junto con los modelos preexistentes de desarrollo de aplicaciones.

Si crees que la tecnología sin servidor tendrá un impacto cada vez mayor en la informática cotidiana y en el desarrollo de aplicaciones, entonces es lógico que otras tecnologías crezcan y evolucionen para soportar mejor la tecnología sin servidor. Del mismo modo que JavaScript se hizo omnipresente debido al auge de las aplicaciones basadas en web y navegador, los lenguajes, las herramientas y la infraestructura informática ejercerán nuevas presiones sobre la informática. A su vez, las herramientas que aborden bien estos retos crecerán y prosperarán (por ejemplo, tanto Ruby on Rails como PHP nacieron para la web), mientras que las aplicaciones que no estén bien adaptadas conservarán sus nichos actuales (dentro de 40 años, seguiremos necesitando programadores COBOL para ayudar a los bancos a gestionar sus aplicaciones mainframe).

Implicaciones para las lenguas

El énfasis de Serverless en la gestión de unidades de trabajo conecta y exterioriza dos patrones de lenguaje existentes: inversión de control y principios de diseño reactivo. La inversión de control2 popularizado por el framework Spring, es un modelo en el que el framework controla el flujo del programa, llamando a código específico de la aplicación en momentos determinados. En el modelo de programación reactiva, las aplicaciones se expresan como un conjunto de reacciones a los cambios en las fuentes de datos ascendentes.3 Al externalizar estos patrones de lenguajes específicos, los sistemas sin servidor democratizan el acceso a estas capacidades sin requerir el uso de marcos o herramientas de lenguajes específicos. Por ejemplo, los sistemas sin servidor son naturalmente elásticos ante cantidades variables de trabajo, y el paradigma de las unidades de trabajo se adapta bien tanto a los flujos de control "no me llames, te llamaré" como a un modelo de comunicación basado en mensajes.

Aunque serverless puede proporcionar un andamiaje para apoyar los patrones de diseño de lenguajes y sistemas existentes, también introduce nuevos requisitos:

Puesta en marcha rápida

Vincular la ejecución de la aplicación al trabajo disponible significa que los sistemas sin servidor tienden a ejecutar operaciones de ampliación y reducción con más frecuencia que los sistemas tradicionales. A su vez, esto significa que el inicio (y el cierre) de la aplicación deben ser rápidos y generar poca carga. Los lenguajes compilados y los que tienen procesos JIT ligeros tienen ventaja sobre los lenguajes con procesos JIT pesados o de importación de módulos que deben ejecutarse en cada inicio de la aplicación.

Gestión de fallos

Dado que los sistemas sin servidor se basan en gran medida en el escalado basado en unidades de trabajo, a menudo emplean servicios externos para almacenar el estado o como límites de microservicios. Esto significa que las aplicaciones creadas con un estilo sin servidor están expuestas a muchas llamadas a servicios remotos, cada una de las cuales puede fallar o agotarse por problemas de red.

Almacenamiento en red sobre almacenamiento en disco

El almacenamiento en disco local en entornos sin servidor tiende a ser muy efímero. Por lo tanto, la capacidad de acceder y gestionar rápidamente archivos en el disco local puede ser menos importante que en las aplicaciones tradicionales, donde las cachés o los resultados precalculados pueden almacenarse en el disco para evitar el trabajo posterior. Al mismo tiempo, la capacidad de llamar fácilmente a los servicios de almacenamiento en red y externalizar el estado fuera de la instancia sin servidor puede ser más importante que en los sistemas tradicionales; por ejemplo, la capacidad de acceder fácilmente a sistemas como Redis o almacenes de objetos como S3 es más crítica cuando el almacenamiento local es realmente efímero.

Serialización

Aunque todas las aplicaciones necesitan serializar y deserializar datos, las aplicaciones sin servidor pueden poner un peso adicional tanto en la facilidad (para los desarrolladores) como en la velocidad y eficiencia (para los ordenadores) de serializar y deserializar datos. Dado que las arquitecturas sin servidor tienden a estar compuestas por microservicios y servicios de datos de respaldo que tienen cada uno sus propios formatos de almacenamiento o de red, la capacidad de serializar y deserializar datos de forma eficiente y sencilla a través de diferentes puntos finales es cada vez más importante.

Implicaciones para el Sandboxing

Las aplicaciones tradicionales han utilizado VMs y contenedores Linux para hacer sandbox de las aplicaciones. Estas herramientas están bien probadas y comprendidas, pero introducen importantes problemas de rendimiento en el arranque, así como sobrecarga para los núcleos, las bibliotecas compartidas y las interfaces de red. Los tiempos de arranque de las máquinas virtuales con un sistema operativo de uso general pueden ser de decenas de segundos, mientras que los contenedores Linux pueden introducir cientos de milisegundos de tiempo de configuración.

Las tecnologías más recientes, como Wasm y los service workers en el tiempo de ejecución de JavaScript, permiten definir sandboxes mucho más restrictivos (sólo se exponen un puñado de métodos de E/S diseñados a medida) que pueden girar en diez milisegundos y tienen unos gastos generales por sandbox de un megabyte o menos. Plataformas como Cloudflare Workers muestran algunas de las promesas de este enfoque, aunque también existen limitaciones sustanciales que probablemente signifiquen que todos los niveles de sandboxing convivirán durante mucho tiempo.4

Implicaciones para el utillaje

El paradigma sin servidor se adapta muy bien a las herramientas para desarrolladores (y a las herramientas generales para no desarrolladores). Por lo general, las herramientas y la automatización se dividen muy bien en unidades de trabajo: construir un binario, generar una API, gestionar un ticket o responder a un mensaje de texto. Dado el tamaño de una función típica, las pruebas de integración pueden ser un enfoque viable para gran parte de la cobertura de la aplicación, en lugar de tener que mantener tanto pruebas unitarias como de integración.

Para los desarrolladores, GitHub Actions es un gran ejemplo de plataforma de herramientas sin servidor. Los desarrolladores pueden escribir acciones que operen sobre un único commit, pull request o release y no necesitan pensar en servidores de larga ejecución, programación de trabajos y concurrencia, o conectar componentes y servicios de la plataforma. Para los no desarrolladores, servicios como IFTTT (If This Then That), que proporcionan automatizaciones sencillas entre servicios empaquetados, ofrecen una experiencia similar sin servidor, sin necesidad de escribir código o scripts de automatización.

Con una plataforma fácil de manejar para las aplicaciones, herramientas como los creadores de aplicaciones de código bajo y sin código y las plataformas de integración se benefician de la ausencia de servidor como sustrato subyacente de la aplicación. A medida que las aplicaciones se convierten menos en grandes procesos en ejecución continua y más en pequeñas cantidades de pegamento entre los servicios existentes, los enfoques de bajo código y sin servidor se complementan entre sí reduciendo los requisitos para que los usuarios escriban y gestionen las aplicaciones.

Implicaciones para la seguridad

Los procesos sin servidor tienden a iniciarse y cerrarse con frecuencia en un conjunto de hosts. Las herramientas de seguridad a nivel de instancia pueden tener dificultades en un entorno dinámico como éste, lo que hace que las herramientas a nivel de clúster sean más importantes y relevantes. Al mismo tiempo, la naturaleza efímera de los procesos sin servidor puede dar una ventaja a los defensores, ya que la rotación natural de las instancias puede erosionar las cabezas de playa de los atacantes tras el éxito inicial del ataque.

Si se observan las tendencias históricas, parece probable que la tecnología sin servidor mejore la capacidad de los defensores para garantizar la aplicación coherente de parches a nivel de sistema operativo. Los formatos de empaquetado coherentes, como los contenedores OCI, también pueden ayudar a la indexación y visibilidad de las aplicaciones creadas con bibliotecas y datos vulnerables. Por desgracia, muchas de las vulnerabilidades de seguridad de alto impacto tienden a manifestarse como defectos a nivel de aplicación, como una validación de entrada insuficiente, errores de control de acceso y errores de diseño. La funcionalidad sin servidor es en gran medida agnóstica a estos fallos; son igualmente graves tanto para las instancias efímeras como para las persistentes, y deben abordarse en otra parte del proceso de diseño del software.

Implicaciones para las infraestructuras

Los retos más obvios de para la infraestructura que soporta las aplicaciones sin servidor están relacionados con el arranque de la aplicación (en particular, los arranques en frío cuando una solicitud está en vuelo) y proporcionar la ilusión de una escala infinita de capacidad y velocidad. Además de los problemas de arranque en frío a nivel de lenguaje mencionados, la infraestructura tiene que hacer llegar el código de la aplicación a la instancia de arranque en frío, y tiene que gestionar este problema para muchas instancias a la vez. Más allá de los tiempos de arranque, las plataformas sin servidor también deben tener en cuenta la gestión de los costes y el aprovisionamiento y desaprovisionamiento eficientes de las instancias, así como la conectividad hacia y desde la plataforma para todas las instancias.

Más allá de los retos cotidianos de las plataformas sin servidor mencionados anteriormente, algunos retos mayores de la infraestructura sin servidor tienen soluciones que no son obvias o "hacen más de lo mismo, pero más rápido".

Uno de los retos del procesamiento de datos es si "enviar datos al código" o "enviar código a los datos". Las actuales arquitecturas sin servidor envían principalmente datos al código, aunque las mejoras en el sandboxing con Wasm pueden cambiar ese equilibrio. Aunque muchas aplicaciones son lo suficientemente pequeñas como para que los gastos generales de ambos enfoques sean similares, la mayoría de las organizaciones tienen al menos unas pocas aplicaciones de datos intensivos para las que los gastos generales de envío y conversión de datos entre diferentes formatos dominan el coste total. Ser capaz de ejecutar estas plataformas de una manera sin servidor y obtener los beneficios de velocidad, coste y eficiencia que de ello se derivan es un problema abierto.

Otro reto relacionado con el trabajo sin servidor es cómo manejar las unidades de trabajo entrelazadas. Mientras cada unidad de trabajo sea independiente, es fácil entender cómo escalar y subdividir el problema para que distintos ordenadores puedan trabajar en aspectos diferentes. Por desgracia, algunos problemas consisten en una mezcla de trabajo fácilmente dividido y trabajo que sintetiza las partes fácilmente divididas en un todo más coherente. Las simulaciones físicas, el procesamiento de flujos y el entrenamiento de redes neuronales son ejemplos en los que parte del trabajo es muy independiente, mientras que otra parte requiere una estrecha coordinación entre los componentes informáticos. Aunque la tecnología sin servidor puede utilizarse para gestionar las partes fácilmente divididas, no es muy útil tener que cruzar plataformas y paradigmas para obtener los beneficios de la tecnología sin servidor sólo para una parte de la solución. Los mecanismos para tender puentes fácilmente entre los patrones informáticos sin servidor y los más convencionales ayudarán a ampliar la gama de problemas que puede abordar sin servidor.

Resumen

Sin servidor no consiste sólo en facilitar la ejecución de servicios de software. Unos servicios de software más sencillos hacen viables nuevas arquitecturas, lo que a su vez permite a los equipos y organizaciones cambiar su modelo de desarrollo de aplicaciones. Las nuevas formas de construir aplicaciones (y las nuevas herramientas que soportan estos patrones) cambian las restricciones de entrega y prueba del software. Las nuevas formas de ejecutar aplicaciones permiten nuevos procesos empresariales, como evaluar el coste por operación y el ROI de las iniciativas de software. En la siguiente parte, veremos cómo aplicar la tecnología sin servidor a la arquitectura de sistemas y al diseño de software para obtener estas ventajas, pero la arquitectura de software está al servicio de las necesidades de la organización, ¡no al revés!

1 Si las API entre estos componentes cambian rápida y descuidadamente, de modo que haya que coordinar los empujes entre componentes, puedes tener un monolito distribuido. Esto es tanto un problema cultural como técnico .

2 A veces se describe con el principio de Hollywood: "No nos llames, te llamaremos".

3 Aunque la programación reactiva no tiene un eslogan tan claro como la inversión de control, ha demostrado impresionantes mejoras de rendimiento en comparación con un modelo tradicional de hilos por petición.

4 Para más detalles sobre Cloudflare Workers en concreto, consulta la charla de Kenton Varda en la QCon de Londres de 2022: "Fine-Grained Sandboxing with V8 Isolates".

Get Construir aplicaciones sin servidor en Knative now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.