En este artículo, analizaremos todo lo que necesita saber sobre los conceptos básicos del manejo de errores de AWS Lambda y algunos métodos populares que utilizan StepFunctions y X-Ray. Independientemente de si es un experto en AWS Lambda o si es un nuevo usuario de Lambda, siempre hay algo nuevo que aprender . Probablemente ya haya encontrado errores de Lambda que pueden parecer bastante desafiantes, ya que el mecanismo que ejecuta los reintentos de Lambda a menudo hará que sea increíblemente difícil hacer un seguimiento de los cambios que ocurren dentro de su aplicación sin servidor.
Serverless no se trata solo de la ejecución directa de código en la función Lambda, sino que es un tipo diferente de arquitectura de todo su sistema . Los nodos distribuidos dentro de esta arquitectura que se activan gracias a eventos asíncronos son lo que hace este sistema.
Cada nodo debe diseñarse como una parte singular con su propia API.
Para aprender a definir todos estos nodos con precisión, debe saber cómo manejar los errores de Lambda . Además, también es necesario tratar adecuadamente el comportamiento de reintento de Lambda.
Por lo tanto, pasemos directamente a cómo funcionan los reintentos y los errores de AWS Lambda , así como cuál es el alboroto en torno a todo esto.
Las funciones Lambda pueden fallar ( lo harán ), y cuando lo hacen, es debido a una de estas situaciones:
Falta de memoria : si no tiene memoria, Lambda a menudo termina con el mensaje "Se cerró el proceso antes de completar la solicitud". El 'Tamaño de la memoria' es siempre el mismo que el de 'Memoria máxima utilizada'. Puede obtener más información sobre la asignación de recursos y la memoria AWS Lambda aquí.
Excepción no controlada generada : puede ocurrir debido a un error de programación, una falla de una API externa o si recibió una entrada no válida.
Tiempo de espera: el mensaje "Tarea expiró después de X segundos" aparece cuando Lambda se cierra violentamente porque se ejecutó más tiempo que la duración del tiempo de espera preconfigurado. El valor máximo es de cinco minutos, mientras que el valor predeterminado se establece en seis segundos.
Cuando ocurre una falla, y ocurrirá en algún momento, lo más probable es que observe reintentos de Lambda en función de estos comportamientos :
Eventos basados en transmisiones: si los eventos actuales son únicamente transmisiones de DynamoDB y AWS Kinesis Data Streams. Cuando sucede, AWS vuelve a activar estas funciones de Lambda fallidas hasta que se procesan correctamente o hasta que caducan los datos, y AWS bloqueará el origen del evento hasta que suceda.
Eventos síncronos : en orígenes de eventos como la invocación síncrona o API Gateway mediante el SDK, la aplicación invocada es responsable de crear reintentos basados en respuestas que obtiene de Lambda . Este escenario de caso es el menos interesante ya que se parece al manejo monolítico de errores.
Eventos asíncronos : la invocación de Lambda ocurre de forma asíncrona para la mayoría de los orígenes de eventos. Esto significa que ninguna aplicación responderá al fallo. Por lo tanto, el marco de AWS se encargará de ello por sí solo . Activará Lambda nuevamente con exactamente el mismo evento, que ocurre principalmente dos veces dentro de los próximos 3 minutos (en algunos casos esporádicos, toma hasta seis horas, mientras que puede ocurrir una cantidad diferente de reintentos continuos).
En caso de que todos los reintentos fallen, es obligatorio registrar este evento en lugar de desecharlo. Es por eso que la función crucial Dead Letter Queue (DLQ) permite la configuración de DLQ a través de AWS SQS que recibirá este tipo de evento. Consecuencias del comportamiento de reintento de AWS Lambda
Cada Lambda se puede ejecutar varias veces con la misma entrada , mientras que la "persona que llama" no sabía que estaba sucediendo. Para realizar con éxito la misma operación varias veces, Lambda tiene que ser 'idempotente'.
La idempotencia significa que no se producirán efectos adicionales cuando se ejecuta con la misma entrada más de una vez.
Vale la pena mencionar que las funciones sin servidor no son el único ejemplo cuando se trata de términos de idempotencia . Un modelo estándar es la red API: cuando una solicitud no recibe respuesta, la misma solicitud se enviará repetidamente.
Por ejemplo, en las arquitecturas sin servidor, puede llegar a un caso similar cuando Lambda obtiene un tiempo de espera antes de recibir una respuesta. Aunque es algo muy inesperado, en algunos casos, un manejo de reintento incorrecto puede ser la causa de problemas graves (una violación estructural de la base de datos (DB)).
La definición de idempotencia establece que es la propiedad de operaciones específicas en informática y matemáticas. Es aplicable varias veces sin alterar el resultado más allá de la primera aplicación. Sin embargo, todavía es algo confuso.
¿Qué sucede si desea ejecutar la misma operación varias veces y en realidad no es un reintento?
Digamos que Lambda recibió un registro de operación de usuario como entrada y es el único responsable de registrar ese registro de operación en una base de datos. En este ejemplo, tendremos que diferenciar entre la entrada del activador de Lambda y un caso de reintento, ya que son lo mismo porque el usuario ha iniciado la misma operación nuevamente.
Hacer referencia al ID de solicitud de Lambda como parte de la entrada en sí es la solución correcta. Solo cuando haya un reintento de Lambda, obtendrá el mismo ID. Para poder extraerlo, utilice context.awsRequestId dentro de Node.js o el campo correspondiente en cualquier otro idioma. Lo que hace este método es proporcionar el enfoque general que buscará ejecuciones de reintento.
No siempre es una solución conveniente utilizar la ID de solicitud por ser un idempotente genuino. Es posible que haya notado en el ejemplo anterior que esta ID también debería haberse guardado en la base de datos. De esa forma, las siguientes invocaciones se darían cuenta si es necesario agregar un nuevo registro. Hay una solución más, y está usando algún almacén de datos en memoria . Sin embargo, podría agregar una sobrecarga bastante significativa.
El manejo de errores de AWS Lambda se puede realizar de diferentes maneras, como utilizar contenedores. Por otro lado, AWS Step Functions ha demostrado ser increíblemente beneficioso para crear una aplicación sin servidor que se ocupará de los reintentos y los errores de forma adecuada, lo que convierte a Step Functions en una solución eficaz. Puede obtener más información sobre AWS Step Functions en nuestra Guía definitiva de Step Functions.
Da el siguiente paso
Digamos que la aplicación tiene que realizar múltiples operaciones en respuesta a un evento . Al combinarlos todos con el mismo Lambda, el código deberá verificar cada operación por separado .
Si está tratando de mantener su Lambda idempotente, ¿debería rehacerse?
Recuerde que esto puede causar fuertes dolores de cabeza. Sería útil si aprendiera la diferencia entre las aplicaciones monolíticas y el ejemplo de la función de paso que hemos mencionado. En una aplicación monolítica, la propia aplicación puede ser responsable de forzar reintentos porque es capaz de esperar entre ellos, y eso es algo que no es posible en Serverless .
Sin embargo, con Step Functions, puede ejecutar todas las operaciones en Lambda por separado. Además, puedes definir transiciones adecuadas entre ellos para cada caso específico. También puede controlar el comportamiento de los reintentos: su duración de retraso y su número. De esa forma, rápidamente lo ajustarás para que sea el más adecuado para tu caso particular. Incluso lo deshabilitará cuando crea que ese es el paso correcto a seguir. Incluso si lo necesita una sola Lambda, la creación de una máquina de pasos es posiblemente la solución más sencilla para deshabilitar el comportamiento de reintento no deseado.
Como probablemente sepa, todos los activadores de función de paso disponibles son bastante limitados ; los únicos disparadores que están disponibles son API Gateway, incluida una ejecución manual utilizando SDK.
Para implementar con éxito este Lambda, debe utilizar el marco Serverless , junto con el increíble complemento 'serverless-resources-env' para que pueda pasar fácilmente el ARN de la máquina de estado . Además, debe asegurarse de usar 'pseudoparámetros sin servidor' y 'funciones de paso sin servidor' para poder definir la máquina de estado como se muestra en el siguiente ejemplo:
Puede ver que la elección artificial de implementar un evento SNS se hace a propósito para activar la máquina de estado , y es accesible como entrada en el paso inicial de Lambda. Todo se volverá idempotente ya que deliberadamente nombramos la ejecución de la máquina de estado como el invocador 'ID de solicitud de Lambda'. En caso de que se produzca un reintento con este invocador Lambda, AWS le otorgará el mismo ID de solicitud.
Después de eso, AWS no volverá a ejecutar la máquina de estado porque tiene el mismo nombre. En teoría, el nombre de ejecución de la máquina de estado también es parte de su entrada. Si bien esta solución es ventajosa en numerosos escenarios de casos, debe saber que también agregará una sobrecarga de complejidad significativa, lo que afectará aún más la observabilidad y la depuración generales del sistema.
Es esencial comprender que el mecanismo de manejo de errores de Step Function es bastante diferente al mecanismo de manejo de errores de AWS Lambda. Para cada estado de la tarea, se puede establecer un marcador de posición de duración del tiempo de espera y, en caso de que la tarea no se complete a tiempo, se generará un error de estado.Tiempo de espera. Este tiempo de espera en particular es ilimitado en cierto modo.
Además, en un caso típico de una Tarea que ejecuta una Lambda, el caso no será el mismo. La duración real del tiempo de espera de Lambda se puede determinar únicamente por su valor preconfigurado y no puede prolongarse más utilizando este método. Por lo tanto, es esencial asegurarse de haber configurado el tiempo de espera de la tarea para que sea igual al tiempo de espera de Lambda. El comportamiento de reintento de la tarea está deshabilitado de forma predeterminada y se puede configurar de cierta manera.
La aplicación de muestra del procesador de errores muestra la utilización de AWS Lambda para manejar eventos que provienen de la suscripción de AWS CloudWatch Logs. Ahora, CloudWatch Logs le permitirá invocar una función Lambda si una entrada de registro coincide con un patrón particular . La suscripción dentro de esta aplicación monitoreará el grupo de registro de una función para todas las entradas con la palabra ERROR . En respuesta, invocará una función Lambda del procesador. La función del procesador luego recuperará el flujo de registro completo y los datos de seguimiento de la solicitud que causó este error, y los almacenará para poder usarlos más adelante.
El código de función se puede encontrar en estos archivos:
Procesador: procesador/index.jsError aleatorio: error aleatorio/index.js
Puede implementar rápidamente la muestra en unos minutos a través de AWS CloudFormation y AWS CLI.
Esta aplicación de muestra utiliza estos servicios de AWS:
Amazon S3 , que almacenará la salida de la aplicación y los artefactos de implementación.
Amazon CloudWatch Logs : recopila registros, pero cuando una entrada de registro coincide con un patrón de filtro, también invocará una función.
AWS X-Ray : genera un mapa de servicios, indexa los seguimientos necesarios para la búsqueda y recopila datos de seguimiento.
AWS Lambda : envía todos los datos de seguimiento a X-Ray, envía registros a CloudWatch Logs y ejecuta un código de función.
Una función Lambda generará errores aleatoriamente cuando se encuentre dentro de la aplicación. Si CloudWatch Logs detecta la palabra ERROR en los registros de la función, proporcionará a la función del procesador un evento para su procesamiento.
Evento de mensaje de CloudWatch Logs
Los datos tienen detalles sobre el evento de registro cuando se decodifican. La función utilizará todos estos detalles para identificar con éxito el flujo de registro y analizará el mensaje de registro para obtener el ID de la solicitud particular que ha causado este error.
Datos de eventos de CloudWatch Logs decodificados
La función del procesador utilizará la información obtenida del evento de CloudWatch Logs para descargar el seguimiento de X-Ray y el flujo de registro completo para una solicitud que haya causado un error. Ambos se almacenarán en el depósito de AWS S3. Además, para permitir que el tiempo de seguimiento y el flujo de registro finalicen correctamente, la función esperará un breve período antes de comenzar a acceder a los datos.
Instrumentación de rayos X de AWS
La aplicación utiliza AWS X-Ray para rastrear las invocaciones de funciones y todas las llamadas que las funciones realizan a AWS. X-Ray utiliza los datos de seguimiento recibidos de las funciones para crear un mapa de servicio que es de gran ayuda para la identificación de errores. Este mapa de servicio en particular muestra la función de error aleatorio que genera errores para algunas solicitudes específicas. Además, muestra la función del procesador que llama a CloudWatch Logs, Amazon S3 y X-Ray.
Estas dos funciones configuradas de Node.js ofrecen seguimiento activo dentro de la plantilla y están instrumentadas con el SDK de AWS X-Ray (Node.js) en el código. Junto con el seguimiento activo, las etiquetas Lambda agregarán un encabezado de seguimiento a todas las solicitudes entrantes y enviarán un seguimiento con detalles de tiempo a AWS X-Ray. Además, la función de error aleatorio utiliza X-Ray SDK para registrar la identificación de la solicitud y la información del usuario dentro de las anotaciones. Estas anotaciones se adjuntan al seguimiento, por lo que puede usarlas para ubicar el seguimiento de la solicitud específica.
La función del procesador obtendrá el ID de la solicitud del evento de CloudWatch Logs y utilizará el SDK de AWS para JavaScript para buscar en X-Ray esa solicitud en particular. También utiliza clientes de SDK de AWS , que están instrumentados por el SDK de X-Ray para descargar el flujo de registro y el seguimiento. Después de eso, los almacenará en el cubo de salida. El SDK de X-Ray registrará todas estas llamadas y aparecerán dentro del seguimiento como subsegmentos.
La aplicación se implementa dentro de los dos módulos de Node.js y se implementa con scripts de shell y una plantilla de AWS CloudFormation. Esta plantilla creará la función de procesador , la función de error aleatorio y todos los siguientes recursos de apoyo :
Rol de ejecución : es un rol de IAM que permite la función con permiso para acceder a otros servicios de AWS. Primer function : es una función adicional cuyo objetivo es invocar la función de error aleatorio para crear un grupo de registro específico. Recurso personalizado : es otro recurso personalizado de AWS CloudFormation que invocará la función principal durante la implementación, por lo que se aseguraría de que este grupo de registros en particular exista. Suscripción a CloudWatch Logs : es una suscripción para el flujo de registro que activa la función del procesador cuando la palabra ERROR se registra correctamente. Política basada en recursos : es una declaración de permiso específica sobre la función del procesador que permite la invocación a través de CloudWatch Logs. Depósito de Amazon S3 : es una ubicación de almacenamiento de salida (función de procesador).
Si intenta sortear las limitaciones de integrar Lambda con CloudFormation correctamente, la plantilla presentará una función adicional que se ejecutará durante las implementaciones . Todas las funciones de Lambda siempre vendrán con un grupo de registros de CloudWatch específico que almacenará el resultado de todas las ejecuciones de funciones . Además, este grupo de registro no se creará hasta que la función se haya invocado por primera vez.
Al crear una suscripción que depende de la existencia exclusiva del grupo de registros, la aplicación debe utilizar una tercera función Lambda para invocar la función de error aleatorio. Esta plantilla también incluye el código en línea de la función principal. Cada recurso personalizado de AWS CloudFormation puede invocarlo durante su implementación. Las propiedades DependsOn garantizarán que la política basada en recursos y el flujo de registros se creen antes de la suscripción.
Las arquitecturas sin servidor cambian fundamentalmente la forma en que desarrollamos, implementamos y monitoreamos aplicaciones. Como ya sabe, los servicios como AWS Lambda también vienen con sus propios límites e idiosincrasias: memoria y tiempo de ejecución limitados, comportamiento de reintento y muchos otros pueden crear efectos secundarios que pueden convertirse fácilmente en pesadillas de monitoreo .
Componer múltiples servicios para cómputo, almacenamiento de datos, colas, etc. magnifica el problema. La cantidad de problemas potenciales se multiplica por las interacciones y dependencias en toda la pila de la nube.
Ejecutar tales arquitecturas a escala es aún más desafiante. En cada nivel de tráfico, no podemos esperar que la pila se comporte de manera homogénea. Quizás las funciones de AWS Lambda escalarán más rápido que una base de datos, por ejemplo.
Dashbird está diseñado para proporcionar a los desarrolladores formas de navegar fácilmente por problemas tan complejos mientras logra un alto grado de visibilidad y calidad en cualquier arquitectura sin servidor.
Dashbird fue creado por desarrolladores sin servidor, para que los desarrolladores sin servidor mejoren la supervisión y el funcionamiento específicamente para los servicios de AWS a escala. Al recopilar y filtrar continuamente sus datos de registro , Dashbird detecta automáticamente todas sus excepciones de código, tiempos de espera, errores de configuración y otras anomalías en tiempo real , y le envía una notificación de inmediato si hay un error o si algo está a punto de fallar.
El manejo de errores de AWS Lambda en la arquitectura sin servidor puede parecer bastante confuso, pero por mucho que sea difícil comprender cómo puede afectar a todo el sistema, es vital entenderlo a fondo. Es importante que sepa cómo administrar correctamente el comportamiento de reintentos de AWS Lambda , y lo mismo ocurre con Step Functions . Cada campo de contador de reintentos dentro del parámetro de contexto es, sin duda, una característica que falta.
Además de las técnicas mencionadas en este artículo, existen otros métodos que ayudarán con el manejo de errores de AWS Lambda, y el uso de contenedores es solo un ejemplo.
La arquitectura con Step Functions que hemos discutido hoy es bastante útil en muchos casos, y el manejo de errores de AWS Lambda es uno de ellos. Si bien ayuda a controlar adecuadamente los reintentos de Lambda, también fomenta la separación de elementos , lo cual es una excelente práctica dentro del mundo de Serverless.
También publicado en: https://dashbird.io/blog/aws-lambda-error-handling-step-functions/