Blog de Amazon Web Services (AWS)

Integración de AWS Lambda con Quarkus

Por Gerardo Arroyo, Cofundador de Flecha Roja Technologies S.A. en Costa Rica
Cristian Romero, Arquitecto de Soluciones para Sector Público en AWS

 

AWS Lambda permite ejecutar código sin aprovisionar ni administrar servidores. Se paga sólo por el tiempo de cómputo consumido.

Con Lambda, se puede ejecutar código para casi cualquier tipo de aplicación o servicio backend sin tener que realizar tareas de administración. Sólo hay que cargar el código y Lambda se encargará de todo lo necesario para ejecutar y escalar el código con alta disponibilidad. Se puede configurar el código para que se active automáticamente desde otros servicios de AWS o puede ser llamado directamente desde cualquier aplicación web o móvil.

Quarkus aparece en un contexto donde la evolución de las tecnologías de contenedores, específicamente Kubernetes, modifican las capacidades requeridas por los desarrolladores de Java con estándares de ejecución vistos en otros frameworks como Go o Node.js. Quarkus incorpora optimizaciones en el uso de memoria y en el tiempo de arranque. Esto le permite, en algunos casos, ejecutar el doble de aplicaciones usando la misma cantidad de RAM comparado a otros stacks de Java nativos de nube, o hasta siete veces más instancias cuando el empaquetado se ha hecho como un binario nativo.

Combinando estas dos tecnologías, se obtienen los beneficios de ejecución utilizando AWS Lambda: optimizando costos, estrategia de ejecución y recursos asignados a las funciones con Quarkus, además de menores tiempos de respuesta y agilidad.

En este ejemplo se usará Quarkus 1.7.3-Final, el cual usa por omisión Java 11. La extensión de Quarkus para AWS Lambda está en una fase de preview al momento de escribir este post (Septiembre 2020). Esto debe ser tomado en cuenta a la hora de usarlo en ambientes de producción o con las variantes que surjan entre releases.

 

Generación del Proyecto con Quarkus y su extensión para AWS Lambda

La creación del proyecto puede hacerse de dos formas:

  • Desde una terminal. Con Maven previamente instalado, se debería ejecutar el siguiente script:

mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
-DarchetypeVersion=1.7.3.Final

  • Directamente desde la web de Quarkus Code, seleccionando la extensión de “AWS Lambda” y agregando el identificador apropiado al artefacto. Para este caso, lambda-quarkus, como el ejemplo presentado en la Figura 1.

 

Figura 1. Creación de un proyecto con la extensión de AWS Lambda sobre Quarkus.

 

Dentro del proyecto generado, hay varias clases con código de ejemplo. Una de ellas llamada TestLambda, incluye el método handleRequest que será invocado cada vez que dicha función sea llamada en AWS Lambda.

@Named("test")
public class TestLambda
       implements RequestHandler<InputObject, OutputObject> {

    @Inject
    ProcessingService service;

    @Override
    public OutputObject handleRequest(InputObject input,
                   Context context) {
        return service.process(input)
             .setRequestId(context.getAwsRequestId());
    }
}

Dentro de esta clase hay que notar:

  • El nombre elegido para la clase con la anotación @Named debe ser modificado en la propiedad quarkus.lambda.handler dentro del archivo application.properties. Este último se encuentra en /src/main/resources/.
  • La clase implementa RequestHandler e indica los objetos de entrada y salida en formato JSON.
  • Se puede utilizar inyección de dependencias y contexto (CDI) de un servicio con la anotación @Inject, como se muestra en el ejemplo.
  • El método handleRequest recibe como segundo parámetro el contexto de ejecución de AWS Lambda, y este método se modifica con la lógica buscada a la hora de implementar. En este artículo, dicha lógica será la concatenación de dos parámetros de entrada.

Una vez hechas las modificaciones, se genera el archivo .jar que será usado para ejecutar en AWS Lambda.

mvn clean package

 

Creación de la función en la consola con AWS Lambda

El archivo .jar generado en el paso anterior, se carga al servicio AWS Lambda mediante la Consola de Amazon Web Services. Dentro de la consola, se deberá hacer click en Create function seleccionado el runtime de Java 11 y asignando un nombre adecuado para la función, como se muestra en la Figura 2.

El alcance de este artículo no incluye otros servicios. Sin embargo, se debe tener presente que si se requiere interactuar con buckets de Amazon S3, almacenamiento en Amazon DynamoDB u otros Servicios de AWS, se deberá tener un rol de IAM apropiado. En este ejemplo, en la sección de Permissions, se creará un nuevo rol para AWS Lambda.

 

Figura 2. Creación de la función en AWS Lambda donde se sube el código resultante del primer paso.

 

Si no se hicieron cambios en la estructura de archivos, el handler debe ser exactamente este: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest, como se detalla en la Figura 3.

 

Figura 3. Handler usado para subir el .jar a AWS Lambda.

 

Una vez la función haya sido creada, se debe hacer una prueba para validar que se desplegó de manera adecuada. Las Figuras 4 y 5 muestran los resultados de la ejecución, donde se observa un tiempo de calentamiento y ejecución total de 1,32 milisegundos. Esta ejecución corresponde a la concatenación de dos strings que ingresan como parámetros en el evento de prueba.

 

Figura 4. Configuración del evento de prueba.

Figura 5. Resultados de la ejecución del evento.

 

A través del uso de imágenes nativas, Quarkus puede optimizar este tipo de ejecuciones. En la siguiente sección se detallará este proceso.

 

Usando una imagen nativa

Para generar esta imagen, se debe compilar el proyecto como un ejecutable nativo. Previamente se debe instalar GraalVM 20.2.0, Docker y los pre-requisitos indicados en este link. Luego, se debe ejecutar el siguiente comando. Si la prueba se está haciendo en MacOS, se debe agregar la propiedad -Dnative-image.docker-build=true para indicar a Quarkus que use un build de Docker, pues AWS Lambda requiere un binario linux:

mvn clean install -Pnative -Dnative-image.docker-build=true

El resultado es un archivo llamado function.zip en el directorio target. AWS Lambda requiere que el ejecutable dentro de esta carpeta sea nombrado bootstrap, así que debe revisarse que tenga esta propiedad. Se debe actualizar el ambiente de ejecución de AWS Lambda con el nuevo archivo .zip y seleccionar el tipo de runtime con la opción Custom runtime, como lo muestra la Figura 6.

 

Figura 6. Ajuste del ambiente de AWS Lambda a los nuevos requerimientos.

 

Luego debe agregarse una variable de ambiente: DISABLE_SIGNAL_HANDLERS con el valor true. De no hacerlo, habrá un error de ejecución por incompatibilidades existentes de Quarkus con el ambiente de AWS Lambda.

 

Figura 7. Ajuste de la variable de ambiente.

 

Al repetir la prueba se obtiene un resultado exitoso y además, una mejora significativa en el tiempo de calentamiento y ejecución en frío: en el caso anterior fueron 1,32 milisegundos versus los 0,99 milisegundos de esta segunda ejecución. En despliegues con una lógica robusta, cuyo uso de memoria sea más intensivo, este tipo de optimización será de utilidad para disminuir los tiempos de respuesta.

 

Figura 8. Ejecución exitosa de la segunda prueba.

 

Una manera alternativa de crear, actualizar y eliminar la función es usar el comando manage.sh generado por el arquetipo de Maven.

 

Conclusión

Quarkus y AWS Lambda permiten optimizar los tiempos de respuesta para funciones creadas en Java bajo este framework. Creando imágenes nativas se tendrán mejores resultados, y este procedimiento podrá ser ejecutado desde las respectivas consolas o desde la terminal para brindar flexibilidad en la creación de scripts.

Probar esta forma de ejecución y esta evolución para desarrolladores de Java les dará beneficios en agilidad, robustez y seguridad.


Sobre el autor y editor

Gerardo Arroyo es programador de Java con múltiples certificaciones, Solution Architect Certificado de AWS y conferencista ocasional. Cofundador de Flecha Roja Technologies S.A. en Costa Rica. Flecha Roja Technologies es una empresa costarricense experta en adopción y aceleración del uso de tecnologías en la nube. Desde el 2001 desarrolla soluciones tecnológicas para empresas públicas y privadas con profesionales con importantes certificaciones.

 

 

 

Cristian David Romero es Arquitecto de Soluciones en Amazon Web Services para Sector Público. Cristian ha ayudado múltiples instituciones de Sector Público y Privado en la adopción tecnológica de nube en los últimos 8 años y ha llevado acabo de manera satisfactoria proyectos que marcan impacto social a nivel de ciudadanos y estudiantes alrededor de América Latina.

 

 

 

Sobre los revisores

Giovanni Rodríguez es Arquitecto de Soluciones en Amazon Web Services para el Sector Público. Giovanni ha ayudado a múltiples entidades de gobierno, organizaciones no gubernamentales, y empresas privadas, en Latinoamérica, a cumplir con sus misiones y objetivos de negocio. Le apasionan los temas de cloud, seguridad de la información, y analítica.

 

 

 

Cristian Castellanos es Arquitecto de Soluciones en Amazon Web Services para el Sector Público. Cristian ha ayudado a múltiples instituciones educativas y de gobierno en la adopción de nuevas tecnologías e implementación de soluciones de analítica.