📝 Como listar la concurrencia reservada y aprovisionada de nuestras Lambdas ⚡.

La concurrencia en funciones lambdas se refiere al número de solicitudes que una función puede manejar simultáneamente. Existen dos tipos principales de control de concurrencia:

  • Concurrencia reservada: Establece un límite máximo de instancias simultáneas para una función específica, garantizando que otras funciones no utilicen esa capacidad. No tiene costos y no mejora el Cold start. El límite por cuenta de la concurrencia reservada es de 1000, se puede aumentar a nivel de cuenta.

  • Concurrencia aprovisionada: Mantiene un número fijo de entornos de ejecución pre inicializados para una función, asegurando que estén listos para manejar solicitudes sin demora. Tiene un costo 💵adicional y ayuda a mejorar el Cold Start ❄️. Son Lambdas que están siempre encendidas ⚠️.

Bien, con esto en mente supongamos un escenario donde tenemos una región con más de 70 lambdas desplegadas y por alguna razón, no tenemos control sobre como está distribuida la concurrencia entre estas lambdas.

Con este escenario podemos intentar ir a AWS cli, o crear un Script de Python (u otro lenguaje) para consultar a través del SDK (Boto3), y en ese momento nos daremos cuenta de que posiblemente nos retorne cero cuando el panel de Amazon y el costo nos está indicando que tenemos concurrencia reservada:

💡 Bien, lo que sucede es que no podemos realizar la consulta si el rol o el usuario que estamos usando para consultar no tiene permisos(🔏)para acceder a esta información de las lambdas.

Solución Alternativa y Reutilizable

Como no podría ser de otra manera para quien me ha leído antes, la solución propuesta es una Lambda 😀que haga este trabajo, desplegado con AWS Sam, y que podemos desplegar y destruir de manera rápida y en distintas regiones.

Código Fuente

https://github.com/olcortesb/list-lambda-provisioned-reserved

Repositorio con todo el codigo que se presenta en este post

Los permisos:

El primer punto es definir la infraestructura y definir los permisos correspondientes.

# https://github.com/olcortesb/list-lambda-provisioned-reserved/blob/main/template.yaml 
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: List Lambda provisioned reserved

Resources:                
  ListFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: lambda.lambda_handler
      Runtime: python3.10
      Architectures: [arm64]
      Timeout: 900
      Policies:
        - Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - lambda:GetFunctionConcurrency
                - lambda:ListFunctions
                - lambda:ListProvisionedConcurrencyConfigs
              Resource: "*"

Los permisos relacionados con Provicioned y concurrency son los que permiten acceder a los atributos.

El código:

El código está basado en Boto3 y lo que hacemos es consultar por todas las lambdas y revisar cuáles tienen configuraciones de concurrencia.

# https://github.com/olcortesb/list-lambda-provisioned-reserved/tree/main/src
# Base on https://repost.aws/knowledge-center/lambda-provisioned-reserved-concurrency
import os
import boto3

def lambda_handler(event, context):
        ...
            try:
                response = lambda_client.get_function_concurrency(
                    FunctionName=function_name
                )
                if 'ReservedConcurrentExecutions' in response:
                    count += 1
                    reserved_concurrency = response['ReservedConcurrentExecutions']
                    print(f"{count}. Function Name: {function_name}, Reserved Concurrency: {reserved_concurrency}")  
            except lambda_client.exceptions.ResourceNotFoundException:
                pass
            except Exception as e:
                print(f"Error retrieving concurrency for {function_name}: {e}")
            try:
                response = lambda_client.list_provisioned_concurrency_configs(
                    FunctionName=function_name
                )
                if 'ProvisionedConcurrencyConfigs' in response and response['ProvisionedConcurrencyConfigs']:
                    provisioned_concurrency = response['ProvisionedConcurrencyConfigs'][0]['RequestedProvisionedConcurrentExecutions']
                    count += 1
                    print(f"{count}. Function Name: {function_name}, Provisioned Concurrency: {provisioned_concurrency}")
            except lambda_client.exceptions.ResourceNotFoundException:
                pass
            except Exception as e:
                print(f"Error retrieving provisioned concurrency for {function_name}: {e}")

Resultados

Ale ejecutar la función recorrerá todas las lambdas que tenemos en la región donde la hemos desplegado y validara si tienen configurada concurrencia reservada o provisionada respectivamente, dándonos un listado de las funciones y la cantidad de concurrencia. Para este ejemplo lo sacamos en un log, pero se puede obtener vía API o enviarlo a algún lugar que concentre los reportes de nuestra infraestructura

Function Logs:
START RequestId: 253fe873-d35c-44e2-8593-f6a43b9cecc3 Version: $LATEST
Total functions 75
1. Function Name: fibonacci-x86-n4, Reserved Concurrency: 5
2. Function Name: fibonacci-x86-n4, Provisioned Concurrency: 1
END RequestId: 253fe873-d35c-44e2-8593-f6a43b9cecc3
REPORT RequestId: 253fe873-d35c-44e2-8593-f6a43b9cecc3    Duration: 8857.61 ms ...

Conclusión

  • Probamos como poder obtener los datos de nuestra concurrencia en una región específica.

  • Identificamos los permisos necesarios para que la lambda pueda consultar por estos permisos

  • Sacamos en un log los resultados como prueba básica, pudiendo enviarlos a distintos destinos o devolviendo mediante una API de ser necesario

Referencias

0
Subscribe to my newsletter

Read articles from Oscar Cortes Bracho directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oscar Cortes Bracho
Oscar Cortes Bracho

Cloud Software Engineer