Como configurar solicitações de aquecimento para melhorar o desempenho

Use as solicitações de aquecimento para reduzir a latência da solicitação e da resposta enquanto o código do aplicativo é carregado em uma instância recém-criada.

No App Engine, há uma necessidade constante de carregar o código do aplicativo em uma nova instância. O carregamento de uma instância pode acontecer nas seguintes situações:

  • Quando você reimplanta uma versão do aplicativo.
  • Quando novas instâncias são criadas devido ao carregamento de solicitações que excedem a capacidade do conjunto atual de instâncias em execução.
  • Quando ocorre manutenção e reparo da infraestrutura subjacente ou do hardware físico.

O carregamento do código do aplicativo em uma nova instância pode resultar em solicitações de carregamento. As solicitações de carregamento podem resultar em maior latência das solicitações para seus usuários. Para evitar isso, use as solicitações de aquecimento. Com elas, o código do aplicativo é carregado para uma nova instância antes que as solicitações ativas cheguem a essa instância.

Se as solicitações de aquecimento estiverem ativas no seu aplicativo, ocorrerá uma tentativa de detectar quando o aplicativo precisará de uma nova instância e de uma solicitação de aquecimento para que a inicialização dessa instância seja gerada. No entanto, essas tentativas de detecção não funcionam em todos os casos. Como resultado, é possível que você encontre solicitações de carregamento, mesmo que as solicitações de aquecimento estejam ativadas em seu aplicativo. Por exemplo, se o aplicativo não atender ao tráfego, a primeira solicitação para o aplicativo será sempre de carregamento e não de aquecimento.

Nas solicitações de aquecimento, como em qualquer outra solicitação para seu aplicativo do App Engine, são usadas as instâncias/hora. Na maioria dos casos em que as solicitações de aquecimento estão ativadas, você não notará um aumento na instância/hora porque o aplicativo está apenas sendo inicializado em uma solicitação de aquecimento, e não de carregamento. O uso de instância/hora aumentará se você decidir executar mais operações, como realizar o pré-armazenamento em cache durante uma solicitação de aquecimento. Se você definir min_idle_instances como maior que 0, poderá encontrar solicitações de aquecimento quando essas instâncias forem iniciadas, mas elas permanecerão disponíveis depois desse tempo.

Com a solicitação de aquecimento padrão, todos os arquivos JAR são indexados na memória e o aplicativo e os filtros são inicializados.

Como ativar solicitações de aquecimento

As solicitações de aquecimento são usadas pelo programador do App Engine, em que é feito o controle do dimensionamento automático de instâncias com base na configuração definida pelo usuário. No ambiente de execução do Java do App Engine, as solicitações de aquecimento são ativadas por padrão. Portanto, o App Engine emite solicitações GET para /_ah/warmup, o que permite responder e inicializar o código do aplicativo conforme necessário. Para responder a solicitações de aquecimento, use um dos seguintes métodos:

Como usar um servlet <load-on-startup>
A maneira mais fácil de fornecer a lógica de aquecimento é marcar seus próprios servlets como <load-on-startup> no arquivo de configuração web.xml.
Como usar um ServletContextListener
Permite executar uma lógica personalizada que um dos servlets seja invocado pela primeira vez por meio de uma solicitação de aquecimento ou de uma solicitação de carregamento.
Como usar um servlet de aquecimento personalizado
Com o uso de um servlet de aquecimento personalizado, o método service do servlet é invocado somente durante uma solicitação de aquecimento, não durante solicitações de carregamento.

Talvez seja necessário implementar seu próprio gerenciador para /_ah/warmup dependendo de qual desses métodos você escolher.

Antes de começar

Com as solicitações de aquecimento ativadas, o programador inicia instâncias quando determina que há necessidade de mais instâncias. As solicitações de aquecimento são usadas pelo programador para a inicialização do aplicativo, por isso, você verá os registros mesmo que não sejam processadas pelo aplicativo.

A mensagem a seguir indica solicitações de aquecimento nos 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.

Não há garantia de chamada das solicitações de aquecimento. Em algumas situações, solicitações de carregamento são enviadas no lugar delas, por exemplo, se a instância a ser iniciada for a primeira ou se houver um grande aumento no tráfego. No entanto, haverá uma tentativa de enviar solicitações para instâncias já aquecidas se as solicitações de aquecimento estiverem ativadas.

No Java 8, as solicitações de aquecimento estão ativadas por padrão. Para ativá-las, adicione - warmup à diretiva inbound_services em appengine-web.xml. Como o aquecimento fica ativado por padrão, você só precisará ativá-lo explicitamente se já tiver implantado um aplicativo com solicitações de aquecimento desativadas em appengine-web.xml. Se esse for o caso, você precisará definir o valor <warmup-requests-enabled> como true e, em seguida, reimplantar.

Como usar um servlet <load-on-startup>

A maneira mais fácil de fornecer uma lógica de inicialização é marcar os próprios servlets como <load-on-startup> em web.xml. Esse método não exige mudanças no código do aplicativo e inicializa todos os servlets especificados quando o aplicativo é inicializado.

No seu arquivo web.xml, para os servlets que você quer carregar na inicialização, adicione o elemento <load-on-startup>1</load-on-startup> ao elemento <servlet>. Exemplo:

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

Essas linhas carregam a classe de servlet especificada e invocam o método init() do servlet. A solicitação de aquecimento inicializa os servlets especificados antes de veicular quaisquer solicitações ativas. Porém, se não houver solicitação de aquecimento, os servlets especificados em <load-on-startup> são registrados no momento da primeira solicitação para uma nova instância, resultando em uma solicitação de carregamento. Como observado anteriormente, o App Engine pode não emitir uma solicitação de aquecimento sempre que seu aplicativo precisar de uma nova instância.

Como usar um ServletContextListener

Se você tiver uma lógica personalizada a ser executada antes que qualquer um dos servlets seja invocado, siga estes passos:

  1. Registre um ServletContextListener no seu arquivo web.xml.

    <listener>
      <listener-class>com.company.MyListener</listener-class>
    </listener>
    
  2. Insira uma classe com o servlet e o código do 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.
      }
    }
    

O ServletContextListener é executado durante uma solicitação de aquecimento. São não houver solicitações de aquecimento, ele é executado quando ocorrer a primeira solicitação para uma nova instância. Isso pode resultar em solicitações de carregamento.

Como usar um servlet de aquecimento personalizado

Com o uso de um servlet de aquecimento personalizado, o método service do servlet é invocado somente durante uma solicitação de aquecimento. Se você usar uma lógica de alto custo em um servlet de aquecimento personalizado, será possível evitar o aumento do tempo de carregamento nas solicitações de carregamento.

Para criar um servlet de aquecimento personalizado, substitua a definição do servlet incorporado para _ah_warmup em web.xml:

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