Optimice las funciones sin servidor de Java en Kubernetes

Un inicio más rápido y una huella de memoria más pequeña siempre son importantes en Kubernetes debido al costo de ejecutar miles de módulos de aplicaciones y el ahorro de costos de hacerlo con menos nodos de trabajo y otros recursos. La memoria es más importante que el rendimiento en microservicios en contenedores en Kubernetes porque:

  • Es más caro debido a la persistencia (a diferencia de los ciclos de CPU)
  • Los microservicios multiplican los gastos generales
  • Conviértete en una aplicación monolítica norte microservicios (por ejemplo, 20 microservicios ≈ 20 GB)

Esto tiene un impacto significativo en el desarrollo de funciones sin servidor y el modelo de implementación de Java. Esto se debe a que muchos desarrolladores empresariales han elegido alternativas como Go, Python y Nodejs para superar el cuello de botella de rendimiento, hasta ahora, gracias a Quarkù, una nueva pila Java nativa de Kubernetes. Este artículo explica cómo optimizar el rendimiento de Java para ejecutar funciones sin servidor en Kubernetes usando Quarkus.

Índice

    Diseño para el primer contenedor.

    Los marcos tradicionales en el ecosistema de Java cuestan la memoria y el tiempo de inicio necesarios para inicializar esos marcos, incluido el procesamiento de configuración, el escaneo de classpath, la carga de clases, el procesamiento de anotaciones y la creación de un metamodelo del mundo, que el marco requiere para operar. Esto se multiplica una y otra vez para diferentes marcos.

    Quarkus ayuda a resolver estos problemas de rendimiento de Java "desplazando hacia la izquierda" la mayor parte de la sobrecarga en tiempo de compilación. Al realizar análisis de código y marco, transformación de código de bytes y generación de metamodelo dinámico solo una vez, en tiempo de compilación, obtiene un ejecutable de tiempo de ejecución altamente optimizado que se inicia muy rápido y no ocupa toda la memoria de un inicio tradicional porque el trabajo es hecho una vez, en la fase de construcción.

    Más importante aún, Quarkus le permite crear un archivo ejecutable nativo que proporciona ventajas de rendimiento, incluidos tiempos de arranque increíblemente rápidos y memoria de tamaño de conjunto residente (RSS) increíblemente pequeño, para un aumento instantáneo y uso de memoria de alta densidad sobre la pila de Java nativa de la nube tradicional.

    Aquí hay un ejemplo rápido de cómo crear el ejecutable nativo con un proyecto de función Java sin servidor usando Quarkus.

    1. Cree el proyecto Maven sin servidor de Quarkus

    Este comando genera un proyecto de Quarkus (ej. quarkus-serverless-native) para crear una función simple:

    $ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create
           -DprojectGroupId=org.acme
           -DprojectArtifactId=quarkus-serverless-native
           -DclassName="org.acme.getting.started.GreetingResource"

    2. Crea un ejecutable nativo

    Se requiere un GraalVM para crear un ejecutable nativo para la aplicación Java. Puede elegir cualquier distribución de GraalVM, como Oracle GraalVM Community Edition (CE) Y Huso (la distribución descendente de Oracle GraalVM CE). Mandrel está diseñado para admitir la creación de ejecutables nativos de Quarkus en OpenJDK 11.

    Abrir pom.xml, y encontrarás esto native perfil. Lo usará para crear un ejecutable nativo:

    <profiles>
        <profile>
            <id>native</id>
            <properties>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>

    Nota: Puede instalar la distribución GraalVM o Mandrel localmente. También puede descargar la imagen del contenedor de Mandrel para compilarla (como hice yo), por lo que debe ejecutar un motor de contenedor (por ejemplo, Docker) localmente.

    Suponiendo que ya inició el tiempo de ejecución del contenedor, ejecute uno de los siguientes comandos de Maven.

    Para Estibador:

    $ ./mvnw package -Pnative
    -Dquarkus.native.container-build=true
    -Dquarkus.native.container-runtime=docker

    Para Podman:

    $ ./mvnw package -Pnative
    -Dquarkus.native.container-build=true
    -Dquarkus.native.container-runtime=podman

    La salida debe terminar con BUILD SUCCESS.

    Ejecute el ejecutable nativo directamente sin Java Virtual Machine (JVM):

    $ target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner

    La salida se verá así:

    __  ____  __  _____   ___  __ ____  ______
     --/ __ / / / / _ | / _ / //_/ / / / __/
     -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /  
    --________/_/ |_/_/|_/_/|_|____/___/  
    INFO  [io.quarkus] (main) quarkus-serverless-native 1.0.0-SNAPSHOT native
    (powered by Quarkus xx.xx.xx.) Started in 0.019s. Listening on: http://0.0.0.0:8080
    INFO [io.quarkus] (main) Profile prod activated.
    INFO [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy]

    ¡Supersónico! Es decir 19 milisegundos en el inicio. El tiempo puede ser diferente en su entorno.

    También tiene un uso de memoria extremadamente bajo, como Linux ps relaciones de utilidad. Mientras se ejecuta la aplicación, ejecute este comando en otro terminal:

    $ ps -o pid,rss,command -p $(pgrep -f runner)

    Deberías ver algo como:

      PID    RSS COMMAND
    10246  11360 target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner

    Este proceso está usando alrededor 11 MB memoria (RSS). ¡Lo suficientemente compacto!

    Nota: El uso de RSS y memoria de cualquier aplicación, incluido Quarkus, varía según el entorno específico y aumentará a medida que se cargue la aplicación.

    También puede acceder a la función con una API REST. Entonces la salida debe ser Hello RESTEasy:

    $ curl localhost:8080/hello
    Hello RESTEasy

    3. Distribuir funciones al servicio Knative

    Si aún no lo has hecho, crear un espacio de nombres (por ejemplo, quarkus-serverless-native) sobre OK (OpenShift Kubernetes Distribution) para distribuir este ejecutable nativo como una función sin servidor. Luego agrega un quarkus-openshift extensión para la distribución del servicio Knative:

    $ ./mvnw -q quarkus:add-extension -Dextensions="openshift"

    Agregue las siguientes variables en src/main/resources/application.properties para configurar los recursos de Knative y Kubernetes:

    quarkus.container-image.group=quarkus-serverless-native
    quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
    quarkus.native.container-build=true
    quarkus.kubernetes-client.trust-certs=true
    quarkus.kubernetes.deployment-target=knative
    quarkus.kubernetes.deploy=true
    quarkus.openshift.build-strategy=docker

    Cree el ejecutable nativo y luego impleméntelo directamente en el clúster de OKD:

    $ ./mvnw clean package -Pnative

    Nota: Asegúrese de estar accediendo al proyecto correcto (p. quarkus-serverless-native) utilizando el oc login mando de antemano.

    La salida debe terminar con BUILD SUCCESS. Llevará unos minutos completar una compilación binaria nativa e implementar un nuevo servicio Knative. Después de crear con éxito el servicio, debería ver un Servicio Knative (KSVC) y una Revisión (REV) usando el archivo kubectl o oc herramienta de comando:

    $ kubectl get ksvc
    NAME                        URL   [...]
    quarkus-serverless-native   http://quarkus-serverless-native-[...].SUBDOMAIN  True

    $ kubectl get rev
    NAME                              CONFIG NAME                 K8S SERVICE NAME                  GENERATION   READY   REASON
    quarkus-serverless-native-00001   quarkus-serverless-native   quarkus-serverless-native-00001   1            True

    4. Accede a la función ejecutable nativa

    Recupere el punto final de la función sin servidor haciendo esto kubectl mando:

    $ kubectl get rt/quarkus-serverless-native

    La salida debería verse como:

    NAME                         URL                                                                                                          READY   REASON
    quarkus-serverless-native   http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN   True

    Accede a la ruta URL con un curl mando:

    $ curl http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN/hello

    En menos de un segundo, obtendrá el mismo resultado que obtuvo localmente:

    Hello RESTEasy

    Cuando acceda a los registros del pod de ejecución de Quarkus en el clúster de OKD, verá que el ejecutable nativo se ejecuta como un servicio de Knative.

    ¿Que sigue?

    Puede optimizar las funciones sin servidor de Java con las distribuciones de GraalVM para implementarlas como funciones sin servidor en Knative con Kubernetes. Quarkus permite esta optimización del rendimiento mediante el uso de configuraciones simples en microservicios normales.

    El siguiente artículo de esta serie lo guiará en la creación de funciones portátiles en varias plataformas sin servidor sin cambios en el código.

    Artículos de interés

    Subir