Mengonfigurasi Warmup Request untuk Meningkatkan Performa

Anda dapat menggunakan warmup request untuk mengurangi latensi permintaan dan respons saat kode aplikasi sedang dimuat ke instance yang baru dibuat.

App Engine sering kali perlu memuat kode aplikasi Anda ke instance baru. Pemuatan instance dapat terjadi dalam situasi berikut:

  • Saat Anda men-deploy ulang versi aplikasi.
  • Saat instance baru dibuat karena beban dari permintaan yang melebihi kapasitas kumpulan instance yang sedang berjalan saat ini.
  • Saat pemeliharaan dan perbaikan infrastruktur atau hardware fisik yang mendasarinya terjadi.

Pemuatan kode aplikasi Anda ke instance baru dapat menyebabkan permintaan pemuatan. Permintaan pemuatan dapat menyebabkan peningkatan latensi permintaan bagi pengguna, tetapi Anda dapat menghindari latensi ini menggunakan warmup request. Warmup request memuat kode aplikasi Anda ke dalam instance baru sebelum permintaan langsung mencapai instance tersebut.

Jika warmup request diaktifkan untuk aplikasi Anda, App Engine akan mencoba mendeteksi kapan aplikasi memerlukan instance baru dan memulai warmup request untuk melakukan inisialisasi instance baru. Namun, upaya deteksi ini tidak berfungsi pada setiap kasus. Akibatnya, Anda mungkin menemukan permintaan pemuatan, meskipun warmup request diaktifkan di aplikasi Anda. Misalnya, jika aplikasi Anda tidak melayani traffic, permintaan pertama ke aplikasi akan selalu berupa permintaan pemuatan, bukan warmup request.

Warmup request menggunakan jam instance seperti permintaan lainnya ke aplikasi App Engine Anda. Dalam sebagian besar kasus jika warmup request diaktifkan, Anda tidak akan melihat peningkatan jam kerja instance karena aplikasi hanya melakukan inisialisasi dalam warmup request, bukan permintaan pemuatan. Penggunaan jam instance dapat meningkat jika Anda memutuskan untuk melakukan lebih banyak pekerjaan, seperti pra-caching selama warmup request. Jika menetapkan min_idle_instances menjadi lebih besar dari 0, Anda mungkin akan menerima warmup request saat instance tersebut pertama kali dimulai, tetapi akan tetap tersedia setelah itu.

Mengaktifkan warmup request

Warmup request digunakan oleh penjadwal App Engine, yang mengontrol penskalaan otomatis instance berdasarkan konfigurasi yang disediakan pengguna. Dengan warmup request diaktifkan, App Engine mengeluarkan permintaan GET ke /_ah/warmup. Anda dapat mengimplementasikan pengendali untuk permintaan ini untuk melakukan tugas khusus aplikasi, seperti pra-caching data aplikasi.

Penjadwal memulai instance jika menentukan bahwa diperlukan lebih banyak instance. Warmup request dapat muncul di log meskipun dinonaktifkan karena penjadwal menggunakannya untuk memulai instance.

Perhatikan bahwa warmup request tidak dijamin akan dipanggil. Dalam beberapa situasi, permintaan pemuatan akan dikirim: misalnya, jika instance tersebut adalah yang pertama dimulai, atau jika ada peningkatan traffic yang tajam. Namun, akan ada "upaya terbaik" untuk mengirim permintaan ke instance yang sudah dipanaskan jika warmup request diaktifkan.

Untuk mengaktifkan warmup request, tambahkan elemen warmup di bawah perintah inbound_services dalam file app.yaml, misalnya:

inbound_services:
- warmup

Membuat pengendali Anda

Buat pengendali yang akan memproses permintaan yang dikirim ke /_ah/warmup. Pengendali harus menjalankan logika warmup yang diperlukan oleh aplikasi Anda.


// 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)
}