Configurar pedidos de preparação para melhorar o desempenho

Pode usar pedidos de preparação para reduzir a latência de pedidos e respostas durante o período em que o código da sua app está a ser carregado para uma instância recém-criada.

O App Engine precisa frequentemente de carregar o código da sua app numa instância nova. O carregamento de uma instância pode ocorrer nas seguintes situações:

  • Quando reimplementa uma versão da sua app.
  • Quando são criadas novas instâncias devido à carga de pedidos que excede a capacidade do conjunto atual de instâncias em execução.
  • Quando ocorrem manutenção e reparações da infraestrutura subjacente ou do hardware físico.

Carregar o código da sua app para uma nova instância pode resultar em pedidos de carregamento. Os pedidos de carregamento podem resultar num aumento da latência dos pedidos para os seus utilizadores, mas pode evitar esta latência através de pedidos de preparação. Os pedidos de preparação carregam o código da sua app numa nova instância antes de quaisquer pedidos em direto chegarem a essa instância.

Se os pedidos de preparação estiverem ativados para a sua aplicação, o App Engine tenta detetar quando a aplicação precisa de uma nova instância e inicia um pedido de preparação para inicializar uma nova instância. No entanto, estas tentativas de deteção não funcionam em todos os casos. Como resultado, pode encontrar pedidos de carregamento, mesmo que os pedidos de preparação estejam ativados na sua app. Por exemplo, se a sua app não estiver a publicar tráfego, o primeiro pedido à app será sempre um pedido de carregamento e não um pedido de preparação.

Os pedidos de preparação usam horas de instância como qualquer outro pedido para a sua aplicação do App Engine. Na maioria dos casos em que os pedidos de aquecimento estão ativados, não vai notar um aumento nas horas de instância porque a sua aplicação está simplesmente a ser inicializada num pedido de aquecimento em vez de num pedido de carregamento. A utilização de horas da instância pode aumentar se decidir fazer mais trabalho, como a colocação em cache prévia durante um pedido de aquecimento. Se definir min_idle_instances para um valor superior a 0, pode encontrar pedidos de preparação quando essas instâncias são iniciadas pela primeira vez, mas permanecem disponíveis após esse período.

Ativar pedidos de preparação

Os pedidos de aquecimento são usados pelo programador do App Engine, que controla o dimensionamento automático de instâncias com base na configuração fornecida pelo utilizador. Com os pedidos de preparação ativados, o App Engine envia GET pedidos para /_ah/warmup. Pode implementar controladores para este pedido para realizar tarefas específicas da aplicação, como a colocação em cache prévia dos dados da aplicação.

O programador inicia instâncias quando determina que são necessárias mais instâncias. Os pedidos de preparação podem aparecer nos registos mesmo que estejam desativados, porque o programador os usa para iniciar instâncias.

Tenha em atenção que não é garantido que os pedidos de preparação sejam chamados. Em algumas situações, são enviados pedidos de carregamento. Por exemplo, se a instância for a primeira a ser iniciada ou se houver um aumento acentuado no tráfego. No entanto, será feito um esforço para enviar pedidos a instâncias já aquecidas se os pedidos de aquecimento estiverem ativados.

Para ativar os pedidos de preparação, adicione o elemento warmup à diretiva inbound_services no seu ficheiro app.yaml, por exemplo:

inbound_services:
- warmup

A criar o seu controlador

Crie um controlador que processe os pedidos enviados para /_ah/warmup. O controlador deve executar qualquer lógica de preparação necessária para a sua app.


// Sample warmup demonstrates usage of the /_ah/warmup handler.
package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"cloud.google.com/go/storage"
)

var startupTime time.Time
var client *storage.Client

func main() {
	// Perform required setup steps for the application to function.
	// This assumes any returned error requires a new instance to be created.
	if err := setup(context.Background()); err != nil {
		log.Fatalf("setup: %v", err)
	}

	// Log when an appengine warmup request is used to create the new instance.
	// Warmup steps are taken in setup for consistency with "cold start" instances.
	http.HandleFunc("/_ah/warmup", func(w http.ResponseWriter, r *http.Request) {
		log.Println("warmup done")
	})
	http.HandleFunc("/", indexHandler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}

	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

// setup executes per-instance one-time warmup and initialization actions.
func setup(ctx context.Context) error {
	// Store the startup time of the server.
	startupTime = time.Now()

	// Initialize a Google Cloud Storage client.
	var err error
	if client, err = storage.NewClient(ctx); err != nil {
		return err
	}

	return nil
}

// indexHandler responds to requests with our greeting.
func indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	uptime := time.Since(startupTime).Seconds()
	fmt.Fprintf(w, "Hello, World! Uptime: %.2fs\n", uptime)
}