Métricas y alarmas de recursos AWS

Imagina que tienes un servicio que funciona con arquitectura serverless, tienes varios procesos divididos en lambdas que conforman una Step Function y necesitas monitorear y saber cada vez que se invoca o falla una lambda en particular o falla un StateMachine completo. Bueno si tienes esta necesidad o alguna parecida, este post es para ti.

En este artículo aprenderás cual es el flujo que debes seguir cuando quieres implementar una alarma, y también veras 2 ejemplos y las pequeñas diferencias que puedes encontrar en ellos. Así conoceremos CloudWatch y sacarás provecho de sus herramientas para monitorear eficazmente tus recursos en AWS.

Bien, pero ¿por donde partimos?

🧠 Paso 1: Identificando nuestro recurso a monitorear

El primer paso es navegar en el mar de posibilidades en cuanto a métricas en CloudWatch, para eso desde la consola podemos ir directamente a CloudWatch, una vez ahí buscar en el panel la sección de Métricas, luego a Todas las métricas.

Bien ahora te puedes encontrar abrumado con la cantidad de opciones, pero, para continuar con el ejemplo buscaremos una métrica en particular, aunque como puedes observar en la siguiente imagen, prácticamente cualquier recurso se puede monitorear, como las llamadas a una API en API Gateway, la capacidad de una tabla en DynamoDB o número de mensajes notificados a través de SNS.

🧠 Paso 2: Eligiendo las métricas

En esta ocasión tomarás dos tipos de métricas, de las más comunes, con sus opciones y verás pequeñas diferencia que para nuestra tristeza no se especifican en documentaciones oficiales de AWS.

Busca una métrica Lambda, y otra métrica de Estado para un StateMachine.

Métrica Lambda: Aquí verás 3 opciones que puedes usar, lo más efectivo para monitorear un lambda en solitario es usar Por nombre de función. Estas son: Duración, Errores, Invocaciones, Limitaciones, ConcurrentExecutions y UnreservedConcurrentExecutions. Usaremos Invocaciones y Errores en este ejemplo.

Métrica de Estados: Al igual que en las lambdas las de estados pueden ser definidas de varias formas, para este ejemplo usarás las Métricas de ejecución. Estas son: ExecutionsSucceeded, ExecutionsFailed, ExecutionsAborted, ExecutionThrottled, ExecutionsTimedOut, ExecutionsStarted y ExecutionTime. Usarás ExecutionsFailed en este ejemplo.

💬 Datos Importantes sobre las métricas:

Bien voy a aclarar un par de datos importantes sobre las métricas.

Las métricas se pueden crear y monitorear a través de un gráfico en la consola de AWS. Ya sea seleccionándola en Métricas/Todas las métricas o bien creando un panel/Dashboard personalizado para una o varias métricas. Si. Veremos ejemplos de como crear paneles para agregar tus gráficos y mantener todo más ordenado y organizado.

Sin embargo, hay otro elemento de las métricas que usaremos en este post, y son las alarmas. Estas nos ayudan junto con el servicio SNS, a no tener que estar constantemente revisando los gráficos en la consola si no que podemos elegir que nos envíe un correo cuando falle o cuando se exceda un limite en determinado recurso.

🧠 Paso 3: Cómo se define una métrica

Bien vamos a ver como se define la métrica, según la documentación oficial, tenemos muchos campos posibles, algunos obligatorios o otros opcionales, puedes ver más aquí: https://docs.aws.amazon.com/es_es/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html. Pero yo te daré un ejemplo a continuación:

Este es un ejemplo de cómo se verían definidas dos alarmas para un Lambda, una que avisa cada vez que se invoca la función y otra cada vez que falla.

💡 Este es un ejemplo de como se verían definidas dos alarmas para un Lambda, una que avisa cada vez que se invoca la función y otra cada vez que falla.

-- CODE language-json -- { "LambdaExampleInvocation": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "AlarmName": "${self:custom.prefix}-lambdaExample-invocation", "AlarmDescription": "Invocación de un lambda es 0", "AlarmActions": [ "${self:custom.stageVars.snsToAlarmNotification}" ], "Namespace": "AWS/Lambda", "MetricName": "Invocations", "Statistic": "Sum", "Period": "3600", "Dimensions": [ { "Name": "FunctionName", "Value": "${self:custom.prefix}-lambdaExample-${opt:stage}" } ], "EvaluationPeriods": "1", "ComparisonOperator": "LessThanOrEqualToThreshold", "Threshold": "0" } }, "LambdaExampleErrorRatio": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "AlarmName": "${self:custom.prefix}-lambdaExample-errors", "AlarmDescription": "Tasa de errores mayor que 0", "AlarmActions": [ "${self:custom.stageVars.snsToAlarmNotification}" ], "Namespace": "AWS/Lambda", "MetricName": "Errors", "Statistic": "Sum", "Period": "3600", "Dimensions": [ { "Name": "FunctionName", "Value": "${self:custom.prefix}-lambdaExample-${opt:stage}" } ], "EvaluationPeriods": "1", "ComparisonOperator": "GreaterThanThreshold", "Threshold": "0" } } }

💡 En este ejemplo se define una alarma para un StateMachine el cual envía un correo cuando este falla una ejecución.

-- CODE language-json -- { "StateMachineExecutionsFailed": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "AlarmName": "StateMachine-Executions-Failed", "AlarmDescription": "StateMachine Failed in Stage: ${self:provider.stage}", "AlarmActions": [{ "Ref": "AlarmEmailNotificationSnsTopic" }], "Namespace": "AWS/States", "MetricName": "ExecutionsFailed", "Statistic": "Maximum", "Period": "60", "Dimensions": [ { "Name": "StateMachineArn", "Value": "arn:aws:states:${self:provider.region}:${self:provider.arnStateMachine}:stateMachine:ExampleNameState" } ], "EvaluationPeriods": "1", "ComparisonOperator": "GreaterThanThreshold", "Threshold": "0", "Unit" : "Count" } } }

💬 Pequeñas Diferencias

Primero, debes tener en cuenta que el nombre de la métrica es el que la define como tal, luego hay campos que definen en tiempo y forma como se visualizará la métrica en el grafico.

Por ejemplo el campo Period, en segundos, durante el cual se aplica la estadística. Esto es necesario para una alarma basada en una métrica. Los valores válidos son 10, 30, 60 y cualquier múltiplo de 60.

✅ Para saber más sobre cada campo del ejemplo: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html

El campo Dimensions es el que define el recurso al que esta conectado y cómo (por nombre o por arn).

Entonces, esta es la diferencia entre definir una lambda y un StateMachine (el lambda está bajo la métrica por nombre y el StateMachine bajo la métrica por el ARN de state).

✅ Sobre el nombre y el valor, se debe considerar que cuando la alarma se define por nombre, el Name puedes dárselo tu a tu elección y el Value debe ser exacto el nombre del recurso, en este caso el Lambda. Sin embargo, en caso de usar arn como Value, el Name debe ser el nombre del recurso mas el arn, en este caso es StateMachineArn. Esta regla puede variar, pero si quieres estar seguro, crea la alarma directamente en la consola a modo de prueba y en ve en Acciones presiona Ver origen.

Esta técnica es muy útil, cuando no conoces bien el servicio o no estas seguro de como definirlo. En este caso esa opción nos abre una ventana como la siguiente, donde podemos ver la definición correcta y automática.

El campo AlarmActions es el que define que servicio o acción se ejecuta al cumplirse la condición de la métrica (en este caso se ejecuta un SNS).

Segundo, el Dashboard tiene una forma de definirse, generalmente en en un dashboard.js y luego un widget .json. En un Dashboard pueden haber n widgets, cada uno reflejando una alarma diferente. Veamos un ejemplo:

-- CODE language-javascript -- #dashboard.js const StateMachine = require('./widgets/StateMachine.json'); module.exports = () => ({ "Type": "AWS::CloudWatch::Dashboard", "Properties": { "DashboardName": "ventaenlinea-sm-dashboardalarm-${self:provider.stage}", "DashboardBody": JSON.stringify(dashboardBody) } }); const dashboardBody = { "widgets": [ { "type": "metric", "x": 0, "y": 0, "width": 15, "height": 3, "properties": StateMachine.StateMachineFailed } ] } #StateMachine.json { "StateMachineFailed": { "view": "timeSeries", "stacked": false, "metrics": [ [ "AWS/States", "ExecutionsFailed", "StateMachineArn", "arn:aws:states:${self:provider.region}:${self:provider.arnMotorVol}:stateMachine:MotorVolSM", { "region": "${self:provider.region}" } ] ], "region": "${self:provider.region}" } }

📌 Dato: Puedes ver la información de la métrica seleccionándola en el panel y yendo a la pestaña Origen.

Los paneles/dashboards se observan de la siguiente manera:

Perfecto, ahora sabes como definir y también que camino seguir cada que quieres monitorizar un recurso en AWS. Pero sé que toda la ayuda sirve, así que prepare un repositorio con una estructura de ejemplo, donde se puede consultar como referenciar en serverless.yml por ejemplo y como manejar variables de entorno como el correo o los arn en diferentes ambientes.

https://github.com/JazminTrujilloEyzaguirre/CloudWatch_ProjectExample

Ultimo dato: Las Alarmas se pueden definir en el mismo proyecto donde tienes tus recursos, por ejemplo tu aplicación, con tus lambdas o tus step functions o también puedes tener un proyecto aparte solo para las alarmas, ya que estas se referencian a través de nombre o arns. Eso te dará orden y te ayudará a no sobrecargar tus proyectos.

Por ultimo, estas alarmas crean e integran el servicio SNS, lo que te permite, agregar correos en los que recibiremos las notificaciones de alarma, para ello debes visualizarlos en la consola.

En Temas puedes visualizar todos los topics que se han creado.

Una vez localizada asegurate que el correo que agregaste está en la sección Suscripciones. Pero para recibir las notificaciones debes subscribirte desde un correo que te llegará similar a este:

Las notificaciónes que debes esperar cuando tu alarma se active sera de este tipo:

Cada recurso, maneja la alarma de las métricas de forma única aunque parecida a primera vista. Espero que este ejemplo te haya ayudado, que sepas por donde partir si tienes una necesidad particular, pero, si aun tienes dudas... Escríbenos! Estamos ansiosos de ayudarte.

Jazmín Trujillo

September 16, 2024