Los arranques en frío aumentan la latencia de las funciones Lambda. Para solucionar este problema, AWS ofrece simultaneidad aprovisionada, que minimiza la latencia del arranque en frío, pero conlleva costos adicionales.
En esta publicación, exploraremos la concurrencia aprovisionada dinámicamente. Esta solución optimiza tanto el costo como el rendimiento, como se demuestra a través de un ejemplo detallado y el código Python de AWS CDK.
Introducción del autor invitado
Noa Gelber es ingeniera de software sénior en CyberArk y se especializa en aplicaciones SaaS sin servidor en AWS. Tiene más de 20 años de experiencia en el desarrollo de software de misión crítica.
Puedes seguir a Noa en su Página de LinkedIn .
Tabla de contenido
Problemas de arranque en frío con Lambda
El inicio en frío de AWS Lambda se refiere al retraso que se experimenta cuando se invoca una función Lambda por primera vez o después de un período de inactividad. Este retraso se produce porque AWS necesita aprovisionar los recursos y la infraestructura necesarios para ejecutar la función, lo que genera latencia antes de que comience el procesamiento de las solicitudes. Una posible solución para mitigar los inicios en frío en AWS Lambda es la concurrencia aprovisionada.
Para obtener más información sobre arranques en frío y optimizaciones Lambda, consulte esta publicación .
Concurrencia aprovisionada
La concurrencia aprovisionada es una característica de Lambda que prepara entornos de ejecución concurrente antes de las invocaciones. Documentación de AWS
La concurrencia aprovisionada garantiza que varias funciones Lambda permanezcan "activas", lo que significa que se inicializan y están preparadas para responder de inmediato, a diferencia de Lambda a pedido, que inicializa los recursos al momento de la invocación. La preinicialización de un entorno incluye tareas como la descarga de código, la configuración del entorno y la ejecución del código de inicialización. Un enfoque común para utilizar la concurrencia aprovisionada es configurar una cantidad fija de dichos entornos. Obtenga más información: Documentación de AWS .
Si bien la simultaneidad aprovisionada ofrece una solución confiable para minimizar la latencia en las funciones de AWS Lambda, puede tener un efecto secundario negativo de aumento de costos, como lo observó nuestro grupo de ingeniería de plataformas en CyberArk .
En las primeras etapas del desarrollo de nuestros servicios SaaS sin servidor, nos topamos con una latencia significativa en varias funciones Lambda. La implementación de la concurrencia aprovisionada resolvió rápidamente este problema. Sin embargo, pronto nos topamos con un aumento notable en los cargos de nuestra cuenta de AWS. Tras una investigación, descubrimos que, durante los períodos de baja carga de trabajo de Lambda, se utilizaba menos del 20 % de las instancias de concurrencia aprovisionada, lo que daba como resultado el pago de recursos no utilizados.
El uso de una cantidad fija de instancias de simultaneidad aprovisionadas no es óptimo en al menos dos escenarios:
Variaciones de tráfico entre cuentas de AWS: algunas cuentas de AWS sirven para fines como probar y simular entornos de producción, mientras que otras se utilizan como entornos de producción. Estas cuentas difieren en sus volúmenes de tráfico, que además varían a lo largo del día.
Variaciones de tráfico regionales: implementar la función Lambda en varias regiones implica lidiar con distintos volúmenes de tráfico. Algunas regiones pueden tener más tráfico que otras.
En situaciones como la anterior, una cantidad fija de instancias suele ser subóptima. Una cantidad fija de instancias elevada da como resultado instancias inactivas y cargos innecesarios durante períodos de poco tráfico, mientras que una cantidad fija de instancias baja genera un aumento en la cantidad de arranques en frío durante picos de tráfico. Una cantidad de instancias que varíe dinámicamente podría tener un mejor rendimiento, optimizando tanto los costos como la latencia.
Concurrencia dinámica aprovisionada al rescate
La solución que presentamos aquí está diseñada para generar ahorros de costos significativos y mejorar la utilización de recursos. Esto se logra mediante la gestión dinámica de la concurrencia aprovisionada mediante el seguimiento de objetivos de escalado automático de aplicaciones . Este enfoque, que ajusta la cantidad de instancias de concurrencia aprovisionadas en respuesta a los cambios en el tráfico de clientes, garantiza una utilización eficiente de los recursos y ahorros de costos sustanciales durante los períodos de poco tráfico. Es importante destacar que todo esto se logra manteniendo un rendimiento de latencia optimizado para las funciones Lambda.
La solución consta de los siguientes componentes clave:
Seguimiento de objetivos de escalado automático de aplicaciones : este componente ofrece escalado de instancias concurrentes aprovisionadas por Lambda sin costos adicionales. Utiliza alarmas y políticas de escalado de CloudWatch. Más información: documentación de AWS .
Política de seguimiento de objetivos: se trata de una política de escalado diseñada para ajustar automáticamente la cantidad de recursos dentro de un grupo de recursos escalable para mantener un valor objetivo específico para una métrica específica. De acuerdo con esta política, la cantidad de instancias de concurrencia aprovisionadas se escala para mantener la Nivel de instancia alineado con el valor objetivo. Para definir políticas de escalado para una función Lambda, Application Auto Scaling requiere registrarla como un objetivo escalable . La métrica puede predefinirse o personalizarse. Más información: Documentación de AWS .
Alarmas de CloudWatch: se crean dos alarmas de CloudWatch durante la implementación de escalamiento automático de la aplicación, una se activa para ampliar las instancias y la otra para reducirlas según la política de seguimiento de destino.
El escalado automático de aplicaciones administra dinámicamente las instancias de concurrencia aprovisionadas dentro de un rango específico mediante el monitoreo de dos alarmas críticas. Estas alarmas se activan en respuesta a los cambios en el valor de una métrica, lo que garantiza que el recuento de instancias se mantenga alineado con el valor objetivo configurado. Para este propósito, utilizaremos una métrica de utilización de concurrencia aprovisionada personalizada.
La primera alarma de CloudWatch se activa cuando la métrica de utilización de simultaneidad aprovisionada supera el valor objetivo durante un período sostenido de más de 3 puntos de datos , con una duración mínima de 3 minutos. En respuesta, el escalado automático de la aplicación aumenta la cantidad de instancias de simultaneidad aprovisionadas.
Por otro lado, la segunda alarma de CloudWatch se activa cuando la métrica de utilización de simultaneidad aprovisionada permanece por debajo del 90 % del valor objetivo durante un período prolongado de 15 puntos de datos , con una duración mínima de 15 minutos. En respuesta, el escalado automático de la aplicación disminuye la cantidad de instancias de simultaneidad aprovisionadas.
Como nota al margen, de manera predeterminada, las alarmas de escalamiento automático de aplicaciones utilizan la estadística promedio de la métrica. Según los documentos de AWS , la métrica de utilización de simultaneidad aprovisionada se debe visualizar utilizando la estadística MAX. Además, es esencial definir una métrica personalizada que tenga como objetivo la estadística máxima para garantizar una gestión eficiente de las cargas de tráfico en ráfagas.
El mecanismo en acción
Considere una función Lambda configurada con simultaneidad aprovisionada y una política de seguimiento de destino, donde la cantidad mínima de instancias se establece en 1, la cantidad máxima de instancias se establece en 5 y el valor objetivo para la métrica de utilización de simultaneidad aprovisionada personalizada se establece en 0,7, lo que representa una utilización del 70 %, según el siguiente ejemplo de AWS .
Ampliación de escala
Las siguientes figuras muestran los resultados de nuestra experimentación con concurrencia aprovisionada dinámica. Al examinar la métrica de utilización de concurrencia aprovisionada en la siguiente figura, observamos que después de una ráfaga repentina a las 17:52, el valor de utilización de concurrencia aprovisionada llegó a 1 , lo que indica una utilización del 100 % de las instancias asignadas. Este valor supera el valor objetivo de 0,7, superando así el umbral de la primera alarma de CloudWatch :
Una vez que se miden 3 puntos de datos para esta métrica, se activa la alarma de escalamiento ascendente de CloudWatch y la política de escalamiento de seguimiento de destino inicia un aumento en las instancias de concurrencia aprovisionadas. Esta acción se puede monitorear en la página de configuración del alias, cuyas capturas de pantalla aparecen a continuación. En este escenario, antes de la ráfaga, hubo dos instancias:
Una vez completada la operación, el número de instancias aumenta a tres.
Reducción de escala
Alrededor de las 18:07, el tráfico disminuye y la utilización de concurrencia aprovisionada también disminuye a 0,3, lo que indica una utilización del 30 % de las instancias, que está por debajo del 90 % del valor objetivo de 0,7, cruzando así el umbral de la segunda alarma de CloudWatch:
Después de 15 puntos de datos consistentes por debajo de la tasa de utilización (15 minutos en nuestro caso), la política de seguimiento de destino activa la operación de reducción, reduciendo la cantidad de instancias a 1.
Solución en profundidad
Ahora que hemos cubierto los elementos clave y visto un ejemplo simple de cómo funcionan en la práctica, repasemos los pasos de implementación con el ejemplo de código CDK:
Este Kit de desarrollo de CD El constructo aplica concurrencia aprovisionada dinámica sobre una función Lambda de acuerdo con estos pasos:
Crear un alias:
Línea 12: Creación de un alias para Lambda, que es necesario para configurar la concurrencia aprovisionada. En este ejemplo, configuramos la cantidad inicial de instancias en 5.
Hasta esta línea, hemos definido una Lambda con configuración de concurrencia aprovisionada utilizando un número estático de instancias.
Crear una métrica personalizada:
Líneas 16 a 21: Cree una métrica personalizada basada en la métrica de utilización de simultaneidad aprovisionada .
El parámetro 'metric_name' representa el nombre de la métrica personalizada.
El parámetro 'estadística' especifica la función de agregación aplicada a los datos métricos.
El parámetro 'unidad' indica la unidad de medida para la estadística de la métrica.
El parámetro 'período' especifica el intervalo de tiempo para recopilar datos métricos que se agregarán en función de una estadística específica. En este caso, el intervalo se configura como 1 minuto, alineándose con la alarma configurada por Application Auto Scaling Target Tracking , que tiene un período de evaluación de 1 minuto.
Ahora, configuraremos la concurrencia aprovisionada dinámica:
Registro de objetivos escalables:
Líneas 23-27: Registra el alias de la función Lambda como un objetivo escalable , definiendo valores mínimos y máximos para la cantidad de instancias de simultaneidad aprovisionadas.
Línea 28: La creación del objeto de destino escalable se define como dependiente del objeto de alias de Lambda.
Definir la política de seguimiento de objetivos:
Línea 29: Configure una política de seguimiento de objetivos basada en el Métrica de utilización de concurrencia aprovisionada que se personaliza con un valor objetivo de 0,7. Sin embargo, se recomienda ajustar este valor según los patrones de tráfico de Lambda.
Advertencias sobre la solución
Establecer el valor objetivo de la métrica
Según mi experiencia personal, si se establece un valor objetivo significativamente más alto que el mínimo, pueden producirse arranques en frío durante picos repentinos de actividad. Es posible que Lambda no escale con la suficiente rapidez para manejar el aumento de carga, lo que genera un aprovisionamiento insuficiente. Dado que el escalamiento lleva un mínimo de 3 minutos, es preferible mantener un cierto nivel de instancias activas listas para procesar solicitudes. Reducir el umbral puede ayudar a prevenir el aprovisionamiento insuficiente al permitir que Lambda escale de manera más agresiva en respuesta al aumento de la demanda.
Por otro lado, si se establece un valor objetivo demasiado bajo dentro del rango, se puede generar un exceso de aprovisionamiento de instancias, lo que no es deseable debido al aumento de los costos. Además, un umbral bajo puede desencadenar eventos de escalamiento frecuentes en respuesta a pequeñas fluctuaciones en la demanda, lo que podría aumentar la latencia.
En última instancia , se trata de encontrar el equilibrio adecuado entre costo y rendimiento y determinar cuánto está dispuesto a invertir para brindar la mejor experiencia al cliente.
Alarma de reducción de escala
Las alarmas de CloudWatch generadas por el seguimiento de objetivos de escalamiento automático de aplicaciones están configuradas para interpretar los datos faltantes como "faltantes". Para obtener más información sobre cómo las alarmas de CloudWatch manejan los datos faltantes, consulte la documentación de AWS .
En cuanto a la alarma de reducción de escala, si no hay tráfico, no habrá ningún dato para la métrica y, en consecuencia, la alarma no se activará. Este escenario podría generar un exceso de aprovisionamiento y costos innecesarios durante los períodos sin tráfico. Por lo tanto, es recomendable establecer el valor de concurrencia aprovisionada inicial en función del patrón de tráfico de la función Lambda. Por ejemplo, las Lambdas que experimentan poco tráfico se pueden inicializar con una cantidad menor de instancias.
Resumen
Vimos cómo podemos reaccionar de manera proactiva a los aumentos de tráfico ajustando la concurrencia aprovisionada, esperando una demanda sostenida o constante. Luego, a medida que disminuye el tráfico, el servicio reduce dinámicamente las instancias aprovisionadas, alineando la asignación de recursos con la carga de trabajo reducida.
Al implementar una solución de concurrencia aprovisionada dinámica, las funciones Lambda pueden mantener una utilización optimizada de la concurrencia aprovisionada , lo que garantiza una asignación eficiente de recursos y ahorros de costos; sin embargo, es importante tener en cuenta que esta no es una solución mágica, realice su investigación y encuentre el equilibrio ideal que se adapte a sus necesidades específicas .
Agradecimientos especiales
Me gustaría agradecer a Ran Isenberg por dedicar su tiempo a revisar esta publicación y compartir sus valiosos conocimientos y comentarios.
A Daniel Urieli por sus útiles debates y sus valiosos comentarios, y a Alon Sadovski por proporcionarnos información valiosa.
留言