Una aplicación basada en eventos bien diseñada utiliza una combinación de AWS servicios y código personalizado para procesar y administrar las solicitudes y los datos. Este capítulo se enfoca en aspectos específicos de Lambda en el diseño de aplicaciones. Hay muchas consideraciones importantes que los arquitectos sin servidor deben tener en cuenta a la hora de diseñar aplicaciones para sistemas de producción con gran actividad.
Muchas de las prácticas recomendadas que se aplican al desarrollo de software y a los sistemas distribuidos también se aplican al desarrollo de aplicaciones sin servidor. El objetivo general es desarrollar cargas de trabajo que sean:
-
Fiables: ofrecen a los usuarios finales un alto nivel de disponibilidad. Los servicios sin servidor de AWS son fiables porque también están diseñados para tolerar errores.
-
Duraderas: ofrecen opciones de almacenamiento que satisfacen las necesidades de durabilidad de la carga de trabajo.
-
Seguras: siguen las prácticas recomendadas y usan las herramientas proporcionadas para proteger el acceso a las cargas de trabajo y limitar el radio de impacto.
-
De buen rendimiento: usan los recursos de computación de forma eficiente y satisfacen las necesidades de rendimiento de los usuarios finales.
-
Rentables: diseñan arquitecturas que eviten costos innecesarios, capaces de escalar sin incurrir en gastos excesivos y que se puedan retirar del servicio sin sobrecargas significativas.
Los siguientes principios de diseño resultan útiles a la hora de crear cargas de trabajo que cumplan estos objetivos. Aunque no todos los principios se aplican a todas las arquitecturas, sirven de guía a la hora de tomar decisiones generales en materia de arquitectura.
Uso de servicios en lugar de código personalizado
Las aplicaciones sin servidor suelen incluir varios servicios de AWS, integrados con código personalizado que se ejecuta en funciones de Lambda. Si bien Lambda se puede integrar con la mayoría de los servicios de AWS, los servicios que se utilizan con más frecuencia en las aplicaciones sin servidor son:
Categoría | Servicio de AWS |
---|---|
Computación |
AWS Lambda |
Almacenamiento de datos |
Amazon S3 Amazon DynamoDB Amazon RDS |
API |
Amazon API Gateway |
Integración de aplicaciones |
Amazon EventBridge Amazon SNS Amazon SQS |
Orquestación |
AWS Step Functions |
Datos y análisis de transmisión |
Amazon Data Firehose |
Existen muchos patrones comunes y bien establecidos en las arquitecturas distribuidas que puede crear usted mismo o implementar mediante servicios de AWS. Para la mayoría de los clientes, invertir tiempo en desarrollar estos patrones partiendo de cero tiene poco valor comercial. Cuando su aplicación necesite uno de estos patrones, utilice el servicio de AWS correspondiente:
Patrón | Servicio de AWS |
---|---|
Cola |
Amazon SQS |
Bus de eventos |
Amazon EventBridge |
Publicar/suscribir (desplegable) |
Amazon SNS |
Orquestación |
AWS Step Functions |
API |
Amazon API Gateway |
Secuencias de eventos |
Amazon Kinesis |
Estos servicios están diseñados para integrarse con Lambda y puede utilizar infraestructura como código (IaC) para crear y descartar recursos en los servicios. Puede utilizar cualquiera de estos servicios a través del AWS SDK
Comprensión de los niveles de abstracción de Lambda
El servicio de Lambda limita el acceso a los sistemas operativos, hipervisores y equipo subyacentes que ejecutan las funciones de Lambda. El servicio mejora y cambia continuamente la infraestructura para agregar características, reducir los costos y aumentar el rendimiento del servicio. El código debe asumir que no conoce la arquitectura de Lambda y que no tiene afinidad por el equipo.
Del mismo modo, AWS administra las integraciones de Lambda con otros servicios con tan solo una cantidad reducida de opciones de configuración expuestas a usted. Por ejemplo, cuando API Gateway y Lambda interactúan, no hay ningún concepto de equilibrio de carga, ya que los servicios administran esto en su totalidad. Tampoco tendrá control directo sobre qué zonas de disponibilidad
Esta abstracción permite centrarse en los aspectos de integración de la aplicación, el flujo de datos y la lógica empresarial, en los que la carga de trabajo aporta valor a los usuarios finales. Permitir que los servicios administren la mecánica subyacente lo ayuda a desarrollar aplicaciones con mayor rapidez y con menos código personalizado que mantener.
Implementación de la ausencia de estado en las funciones
Al crear funciones de Lambda, debe asumir que el entorno existe solo para una única invocación. La función debe inicializar cualquier estado necesario cuando se inicia por primera vez. Por ejemplo, es posible que la función requiera obtener datos de una tabla de DynamoDB. Debe confirmar cualquier cambio de datos permanente en un almacén duradero, como Amazon S3, DynamoDB o Amazon SQS antes de salir. No se debe basar en ninguna estructura de datos ni en archivos temporales existentes, así como en ningún estado interno susceptible de ser administrado por múltiples invocaciones.
Para inicializar las conexiones y bibliotecas de la base de datos, o cargar el estado, se puede aprovechar la inicialización estática. Dado que los entornos de ejecución se reutilizan siempre que es posible para mejorar el rendimiento, puede amortizar el tiempo necesario para inicializar estos recursos en varias invocaciones. Sin embargo, no debe almacenar ninguna variable o dato utilizado en la función dentro de este ámbito global.
Reducción al mínimo del acoplamiento
La mayoría de las arquitecturas deberían preferir muchas funciones más cortas a menos funciones más grandes. El objetivo de cada función debe ser gestionar el evento transferido a la función, sin conocer ni esperar nada del flujo de trabajo general ni del volumen de transacciones. Esto hace que la función sea independiente del origen del evento con un acoplamiento mínimo a otros servicios.
Cualquier constante de alcance global que cambie con poca frecuencia debe implementarse como variable de entorno para permitir las actualizaciones sin implementaciones. Todos los secretos o información confidencial deben almacenarse en Almacén de parámetros de AWS Systems Manager o en AWS Secrets Manager
Creación basada en datos bajo demanda en lugar de lotes
Muchos sistemas tradicionales están diseñados para ejecutarse periódicamente y procesar lotes de transacciones que se han acumulado con el tiempo. Por ejemplo, una aplicación bancaria puede ejecutarse cada hora para procesar las transacciones de los cajeros automáticos en los libros de contabilidad centrales. En las aplicaciones basadas en Lambda, el procesamiento personalizado debe activarse con cada evento, lo que permite al servicio escalar verticalmente la simultaneidad según sea necesario, para proporcionar un procesamiento de las transacciones casi en tiempo real.
Si bien puede ejecutar tareas cron
Por ejemplo, no es recomendable utilizar un proceso por lotes que active una función de Lambda para obtener una lista de nuevos objetos de Amazon S3. Esto se debe a que el servicio puede recibir más objetos nuevos entre lotes de los que se pueden procesar en una función de Lambda de 15 minutos.

En su lugar, Amazon S3 debe invocar la función Lambda cada vez que se introduzca un nuevo objeto en el bucket. Este enfoque se puede escalar significativamente más y funciona casi en tiempo real.

Considere la posibilidad de utilizar AWS Step Functions para la orquestación
Los flujos de trabajo que implican lógica de ramificación, diferentes tipos de modelos de error y lógica de reintentos suelen utilizar un orquestador para realizar un seguimiento del estado de la ejecución general. Evite utilizar funciones de Lambda para este propósito, ya que resulta en un acoplamiento estrecho y un manejo de código complejo para el enrutamiento.
Con AWS Step Functions
Es habitual que los flujos de trabajo más sencillos de las funciones de Lambda se tornen más complejos con el tiempo. Al utilizar una aplicación sin servidor de producción, es importante identificar cuándo ocurre esto para poder migrar esta lógica a una máquina de estados.
Implementación de la idempotencia
Los servicios sin servidor de AWS, incluido Lambda, son tolerantes a errores y están diseñados para gestionar los errores. Por ejemplo, si un servicio invoca una función de Lambda y se produce una interrupción del servicio, Lambda invocará la función en una zona de disponibilidad diferente. Si la función arroja un error, Lambda reintentará la invocación.
Como el mismo evento se puede recibir más de una vez, las funciones deben diseñarse de forma que sean idempotentes
Para implementar la idempotencia en las funciones de Lambda, puede utilizar una tabla de DynamoDB para realizar un seguimiento de los identificadores procesados recientemente y determinar si la transacción ya se ha gestionado anteriormente. La tabla de DynamoDB suele implementar un valor de tiempo de vida (TTL) para hacer caducar los elementos a fin de limitar el espacio de almacenamiento utilizado.
Uso de varias cuentas de AWS para administrar las cuotas
Muchas cuotas de servicio en AWS se establecen a nivel de cuenta. Esto significa que a medida que se agregan más cargas de trabajo, los límites podrían agotarse rápidamente.
Una forma eficaz de resolver este problema es utilizar varias cuentas de AWS, y dedicar cada carga de trabajo a su propia cuenta. Esto evita que las cuotas se compartan con otras cargas de trabajo o recursos ajenos a la producción.
Además, al utilizar AWS Organizations
Un enfoque habitual consiste en proporcionar una cuenta de AWS a cada desarrollador y, a continuación, utilizar cuentas independientes para la fase de implementación y producción de la versión beta:

Bajo este modelo, cada desarrollador cuenta con su propio conjunto de límites asignados a su cuenta, lo que garantiza que su uso no afecte el entorno de producción. Este enfoque también permite a los desarrolladores probar las funciones de Lambda de forma local en sus máquinas de desarrollo con los recursos de la nube activos de sus cuentas individuales.