Configura solicitudes de preparación para mejorar el rendimiento

Puedes usar solicitudes de preparación para reducir la latencia de las respuestas y solicitudes cuando se carga el código de tu app en una instancia recién creada.

Con frecuencia, App Engine necesita cargar el código de tu app en una instancia nueva. La carga de una instancia puede suceder en las siguientes situaciones:

  • Cuando vuelves a implementar una versión de tu app.
  • Cuando se crean nuevas instancias debido a que la carga de solicitudes supera la capacidad del conjunto actual de instancias en ejecución.
  • Cuando se realizan reparaciones y mantenimiento de la infraestructura subyacente o del hardware físico.

Cuando cargas el código de tu app en una instancia nueva, pueden generarse solicitudes de carga. Las solicitudes de carga pueden provocar una mayor latencia de solicitudes para los usuarios. Puedes evitarla si usas solicitudes de preparación. que cargan el código de tu app en una instancia nueva antes de que le lleguen solicitudes reales.

Si habilitaste las solicitudes de preparación en tu aplicación, App Engine intenta detectar cuándo esta necesita una instancia nueva y envía una solicitud de preparación para inicializarla. Sin embargo, estos intentos de detección no funcionan en todos los casos. Como resultado, es posible que encuentres solicitudes de carga, incluso si las solicitudes de preparación están habilitadas en tu app. Por ejemplo, cuando tu app no entrega tráfico, la primera solicitud siempre será de carga, no de preparación.

Las solicitudes de preparación usan horas de instancia como cualquier otra solicitud para tu aplicación de App Engine. En la mayoría de los casos en los que se habilitan las solicitudes de preparación, no se observa un aumento en las horas de instancia porque la aplicación se inicializa con una solicitud de preparación en lugar de una de carga. Tu uso de horas de instancia puede aumentar si decides hacer más trabajo, como almacenar datos en caché de forma previa durante una solicitud de preparación. Si configuras min_idle_instances como un valor mayor que 0, es posible que se generen solicitudes de preparación cuando esas instancias se inicien por primera vez, pero seguirán disponibles después de ese momento.

La solicitud de preparación predeterminada causa que todos los archivos JAR se indexen en la memoria y, además, inicializa tu aplicación y tus filtros.

Habilita las solicitudes de preparación

El programador de App Engine, que controla el ajuste de escala automático de las instancias según la configuración proporcionada por el usuario, usa las solicitudes de preparación. En el entorno de ejecución Java de App Engine, las solicitudes de preparación están habilitadas de forma predeterminada, por lo que App Engine emite solicitudes GET a /_ah/warmup, lo que te permite responder y, además, inicializar el código de la aplicación. Puedes responder a las solicitudes de preparación con uno de los siguientes métodos:

Mediante un servlet <load-on-startup>
La forma más sencilla de proporcionar la lógica de preparación es marcar tus propios servlets como <load-on-startup> en el archivo de configuración web.xml.
Mediante un ServletContextListener
Te permite ejecutar una lógica personalizada antes de que se invoque cualquiera de los servlets a través de una solicitud de preparación o una solicitud de carga.
Mediante un servlet de preparación personalizado
Mediante un servlet de preparación personalizado, puedes invocar el método service del servlet solo durante una solicitud de preparación, en lugar de hacerlo durante las solicitudes de carga.

Es posible que debas implementar tu propio controlador para /_ah/warmup según el método que elijas.

Antes de comenzar

Si las solicitudes de preparación están habilitadas, el programador inicia instancias cuando determina que se necesitan más. El programador usa solicitudes de preparación para iniciar tu app, por lo que verás registros incluso si tu aplicación no procesa esas solicitudes de preparación.

El siguiente mensaje indica las solicitudes de preparación en los registros /_ah/warmup:

This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.

Ten en cuenta que no hay garantía de que se llame a las solicitudes de preparación. En algunas situaciones, se envían solicitudes de carga en su lugar (por ejemplo, si es la primera instancia que se inicia o si el tráfico aumenta de manera repentina). Sin embargo, si las solicitudes de preparación están habilitadas, el sistema hará todo lo posible para enviar las solicitudes a instancias que ya estén preparadas.

En Java 8, las solicitudes de preparación están habilitadas de forma predeterminada. Para habilitarlas, agrega - warmup a la directiva inbound_services en appengine-web.xml. Las solicitudes de preparación están habilitadas de forma predeterminada, por lo que solo deberás habilitarlas de manera explícita si implementaste una aplicación con anterioridad que tuviera las solicitudes de preparación inhabilitadas en appengine-web.xml. De ser así, debes establecer el valor <warmup-requests-enabled> en true y, luego, volver a implementar.

Usa un servlet <load-on-startup>

La forma más sencilla de proporcionar lógica de preparación es marcar tus propios servlets como <load-on-startup> en web.xml. Este método no requiere cambios en el código de tu aplicación y, además, inicializa todos los servlets especificados cuando tu aplicación se inicializa.

En el archivo web.xml, para los servlets que deseas cargar al inicio, agrega el elemento <load-on-startup>1</load-on-startup> al elemento <servlet>. Por ejemplo:

<servlet>
  <servlet-name>my-servlet</servlet-name>
  <servlet-class>com.company.MyServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

Con estas líneas, se carga la clase de servlet especificada y se invoca el método init() del servlet. La solicitud de preparación inicializa los servlets especificados antes de inspeccionar cualquier solicitud en tiempo real. Sin embargo, si no hay una solicitud de preparación, los servlets especificados en <load-on-startup> se registran en la primera solicitud a una instancia nueva, lo que genera una solicitud de carga. Como se mencionó antes, es posible que App Engine no emita una solicitud de preparación cada vez que la aplicación necesite una instancia nueva.

Usa un ServletContextListener

Si cuentas con una lógica personalizada que desees ejecutar antes de que se invoquen tus servlets, sigue estos pasos:

  1. Registra un ServletContextListener en el archivo web.xml.

    <listener>
      <listener-class>com.company.MyListener</listener-class>
    </listener>
    
  2. Proporciona una clase junto con tu servlet y un código de filtro:

    public class MyListener implements ServletContextListener {
      public void contextInitialized(ServletContextEvent event) {
        // This will be invoked as part of a warmup request, or
        // the first user request if no warmup request was invoked.
      }
      public void contextDestroyed(ServletContextEvent event) {
        // App Engine does not currently invoke this method.
      }
    }
    

El ServletContextListener se ejecuta durante una solicitud de preparación. Si no existe una solicitud de preparación, se ejecuta en la primera solicitud a una instancia nueva. Puede dar como resultado solicitudes de carga.

Usa un servlet de preparación personalizado

El servlet de preparación personalizado invoca el método service del servlet solo durante una solicitud de preparación. Colocar las operaciones lógicas costosas en un servlet de preparación personalizado te ayuda a reducir el tiempo de carga de las solicitudes de carga.

Si deseas crear un servlet de preparación personalizado, solo debes anular la definición del servlet integrada para _ah_warmup en web.xml:

<servlet>
  <servlet-name>_ah_warmup</servlet-name>
  <servlet-class>com.company.MyWarmupServlet</servlet-class>
</servlet>