Configurar solicitudes de preparación para mejorar el rendimiento

Puedes usar solicitudes de calentamiento para reducir la latencia de las solicitudes y las respuestas durante el tiempo en el que se carga el código de tu aplicación en una instancia recién creada.

App Engine necesita cargar con frecuencia el código de tu aplicación en una instancia nueva. Una instancia se puede cargar en las siguientes situaciones:

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

Cargar el código de tu aplicación en una instancia nueva puede provocar solicitudes de carga. Las solicitudes de carga pueden provocar un aumento de la latencia de las solicitudes de los usuarios, pero puedes evitarlo con las solicitudes de calentamiento. Las solicitudes de calentamiento cargan el código de tu aplicación en una nueva instancia antes de que lleguen solicitudes activas a esa instancia.

Si las solicitudes de calentamiento están habilitadas en tu aplicación, App Engine intenta detectar cuándo necesita una instancia nueva e inicia una solicitud de calentamiento para inicializarla. Sin embargo, estos intentos de detección no funcionan en todos los casos. Por lo tanto, es posible que se produzcan solicitudes de carga, aunque las solicitudes de calentamiento estén habilitadas en tu aplicación. Por ejemplo, si tu aplicación no sirve tráfico, la primera solicitud a la aplicación siempre será una solicitud de carga, no una solicitud de calentamiento.

Las solicitudes de calentamiento usan horas de instancia como cualquier otra solicitud a tu aplicación de App Engine. En la mayoría de los casos en los que las solicitudes de calentamiento están habilitadas, no notarás un aumento en las horas de instancia, ya que tu aplicación simplemente se inicializa en una solicitud de calentamiento en lugar de en una solicitud de carga. El uso de horas de instancia puede aumentar si decides hacer más trabajo, como pre-caché durante una solicitud de calentamiento. Si asignas a min_idle_instances un valor superior a 0, es posible que se produzcan solicitudes de preparación cuando se inicien esas instancias por primera vez, pero seguirán estando disponibles después de ese tiempo.

La solicitud de calentamiento predeterminada hace que todos los archivos JAR se indexen en la memoria e inicializa tu aplicación y tus filtros.

Habilitar solicitudes de preparación

El programador de App Engine usa las solicitudes de calentamiento, que controla el autoescalado de las instancias en función de la configuración proporcionada por el usuario. En el entorno de ejecución de Java de App Engine, las solicitudes de calentamiento están habilitadas de forma predeterminada, por lo que App Engine envía solicitudes GET a /_ah/warmup, lo que te permite responder e inicializar el código de tu aplicación según sea necesario. Puedes responder a las solicitudes de calentamiento mediante uno de los siguientes métodos:

Usar un servlet <load-on-startup>
La forma más sencilla de proporcionar lógica de calentamiento es marcar tus propios servlets como <load-on-startup> en el archivo de configuración web.xml.
Usar una ServletContextListener
Te permite ejecutar lógica personalizada antes de que se invoque por primera vez cualquiera de tus servlets, ya sea a través de una solicitud de calentamiento o de una solicitud de carga.
Usar un servlet de calentamiento personalizado
Si se usa un servlet de calentamiento personalizado, se invoca el método service del servlet solo durante una solicitud de calentamiento, en lugar de durante las solicitudes de carga.

Es posible que tengas que implementar tu propio controlador para /_ah/warmup en función del método que elijas.

Antes de empezar

Cuando las solicitudes de calentamiento están habilitadas, el programador inicia instancias cuando determina que se necesitan más. El programador usa solicitudes de calentamiento para iniciar tu aplicación, por lo que verás registros aunque tu aplicación no procese esas solicitudes.

El siguiente mensaje indica solicitudes de calentamiento en los registros de /_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 se garantiza que se llamen las solicitudes de calentamiento. En algunos casos, se envían solicitudes de carga. Por ejemplo, si la instancia es la primera que se inicia o si hay un aumento pronunciado del tráfico. Sin embargo, se hará todo lo posible para enviar solicitudes a las instancias que ya se hayan calentado si las solicitudes de calentamiento están habilitadas.

En Java 8, las solicitudes de preparación están habilitadas de forma predeterminada. Para habilitarlas, añade - warmup a la directiva inbound_services en appengine-web.xml. Como el calentamiento está habilitado de forma predeterminada, solo tienes que habilitarlo explícitamente si has desplegado previamente una aplicación con las solicitudes de calentamiento inhabilitadas en appengine-web.xml. En ese caso, debe asignar el valor <warmup-requests-enabled> a true y, a continuación, volver a implementar.

Usar un servlet <load-on-startup>

La forma más sencilla de proporcionar lógica de calentamiento es marcar tus propios servlets como <load-on-startup> en web.xml. Con este método, no es necesario modificar el código de la aplicación y se inicializan todos los servlets especificados cuando se inicializa la aplicación.

En el archivo web.xml, añade el elemento <load-on-startup>1</load-on-startup> al elemento <servlet> de los servlets que quieras cargar al inicio. Por ejemplo:

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

Estas líneas cargan la clase de servlet especificada e invocan el método init() del servlet. La solicitud de preparación inicializa los servlets especificados antes de atender cualquier solicitud activa. Sin embargo, si no hay ninguna solicitud de calentamiento, los servlets especificados en <load-on-startup> se registran en la primera solicitud a una instancia nueva, lo que da lugar a una solicitud de carga. Como se ha indicado anteriormente, es posible que App Engine no envíe una solicitud de preparación cada vez que tu aplicación necesite una instancia nueva.

Usar un ServletContextListener

Si tienes una lógica personalizada que quieres ejecutar antes de invocar cualquiera de tus servlets, haz lo siguiente:

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

    <listener>
      <listener-class>com.company.MyListener</listener-class>
    </listener>
    
  2. Proporciona una clase junto con el código de servlet y 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 calentamiento. Si no hay ninguna solicitud de calentamiento, se ejecuta en la primera solicitud a una instancia nueva. Esto puede dar lugar a solicitudes de carga.

Usar un servlet de calentamiento personalizado

El servlet de calentamiento personalizado invoca el método service del servlet solo durante una solicitud de calentamiento. Si colocas una lógica costosa en un servlet de calentamiento personalizado, puedes evitar que aumenten los tiempos de carga de las solicitudes de carga.

Para crear un servlet de calentamiento personalizado, solo tienes que anular la definición del servlet integrado de _ah_warmup en web.xml:

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