Belajar Echo - Performance & Troubleshooting
Series/Belajar Echo/Episode 19
Episode 19 of 23

Belajar Echo - Performance & Troubleshooting

Episode ini mengoptimasi dan memperbaiki aplikasi Echo: mengurangi alokasi dengan reuse, connection pooling, caching Redis, tuning HTTP server, serta troubleshooting route conflict, error binding, deadlock, kebocoran goroutine, dan migrasi v4 ke v5.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Performa bukan soal mengejar angka benchmark, tapi menghilangkan pemborosan. Episode ini menggabungkan dua sisi: optimasi yang terukur untuk mempercepat aplikasi, dan troubleshooting untuk menemukan akar masalah saat sesuatu berjalan lambat atau salah.

Episode 19 ini membahas pengurangan alokasi dan reuse, connection pooling, caching Redis, tuning HTTP server, serta troubleshooting route conflict, error binding, deadlock, kebocoran goroutine, dan migrasi v4 ke v5.

Optimasi Alokasi dan Reuse

Mengukur Sebelum Mengoptimasi

Jangan mengoptimasi berdasarkan tebakan. Gunakan benchmark dari episode 17 untuk menemukan titik pemborosan:

Benchmark dengan pprof
import _ "net/http/pprof"

Lalu ambil CPU profile saat beban:

Mengambil CPU profile
go test -bench=. -benchmem -cpuprofile=cpu.out ./internal/handler/
go tool pprof -top cpu.out

go tool pprof -top cpu.out menampilkan fungsi yang paling banyak menghabiskan CPU. Optimasi dimulai dari baris teratas daftar ini, bukan dari dugaan.

Mengurangi Alokasi dengan Reuse

Pola umum pemborosan: membuat slice atau buffer baru setiap request. Gunakan sync.Pool untuk objek yang sering dipakai dan mahal dibuat:

Reuse buffer dengan sync.Pool
var bufPool = sync.Pool{
	New: func() any { return bytes.NewBuffer(make([]byte, 0, 4096)) },
}
 
func handler(c echo.Context) error {
	buf := bufPool.Get().(*bytes.Buffer)
	defer bufPool.Put(buf)
	buf.Reset()
	buf.WriteString("hasil proses yang membutuhkan buffer besar")
	return c.Blob(http.StatusOK, echo.MIMETextPlain, buf.Bytes())
}

sync.Pool menyimpan objek yang bisa dipakai ulang antar request, mengurangi alokasi dan beban GC secara signifikan.

Connection Pooling dan Caching

Pooling untuk Database dan Klien HTTP

Pooling bukan hanya untuk database. Klien HTTP keluar juga harus di-pool agar TCP connection dipakai ulang:

Klien HTTP dengan transport reuse
var httpClient = &http.Client{
	Transport: &http.Transport{
		MaxIdleConns:        100,
		MaxIdleConnsPerHost: 20,
		IdleConnTimeout:     90 * time.Second,
	},
}

Satu klien global yang di-pool jauh lebih cepat daripada membuat klien baru per request.

Caching dengan Redis

Redis memangkas latensi untuk data yang jarang berubah. Gunakan Redis sebagai cache di depan query:

Cache with Redis via go-redis
import "github.com/redis/go-redis/v9"
 
func getProduct(ctx context.Context, id int) (*model.Product, error) {
	key := "product:" + strconv.Itoa(id)
	if cached, err := rdb.Get(ctx, key).Result(); err == nil {
		var p model.Product
		if json.Unmarshal([]byte(cached), &p) == nil {
			return &p, nil
		}
	}
	p, err := repo.FindByID(ctx, id)
	if err != nil {
		return nil, err
	}
	data, _ := json.Marshal(p)
	rdb.Set(ctx, key, data, 10*time.Minute)
	return p, nil
}

Pola cache-aside: baca cache dulu, hit database jika kosong, lalu simpan hasilnya dengan TTL.

Tuning HTTP Server

Memilih Nilai Timeout yang Tepat

Episode 10 memperkenalkan http.Server custom. Beberapa nilai tuning tambahan untuk beban produksi:

Server dengan konfigurasi tuning
s := &http.Server{
	Addr:              ":" + cfg.Port,
	ReadHeaderTimeout: 10 * time.Second,
	ReadTimeout:       30 * time.Second,
	WriteTimeout:      30 * time.Second,
	IdleTimeout:       120 * time.Second,
	MaxHeaderBytes:    1 << 20,
}

ReadHeaderTimeout melindungi dari slow-loris, MaxHeaderBytes membatasi ukuran header. Setiap nilai dipilih berdasarkan perilaku klien, bukan angka acak.

Troubleshooting Umum

Route Conflict

Error saat mendaftarkan route yang duplikat: gunakan e.Routes() dan e.Debug = true (episode 4) untuk melihat route yang sudah terdaftar sebelum mendaftarkan yang baru.

Error Binding

Payload yang tidak cocok menghasilkan error binding. Periksa tag struct, Content-Type, dan ukuran body yang dibatasi BodyLimit. Error validasi biasanya membawa pesan field spesifik — tampilkan untuk debugging.

Deadlock dan Kebocoran Goroutine

Deadlock sering berasal dari channel yang tidak pernah dikirim atau dikonsumsi. Kebocoran goroutine muncul saat context tidak dibatalkan — misalnya goroutine yang tidak pernah menerima sinyal cancel. Deteksi dengan pprof:

Melihat goroutine aktif
import _ "net/http/pprof"
Melihat profil goroutine
curl http://localhost:6060/debug/pprof/goroutine?debug=1

/debug/pprof/goroutine menampilkan semua goroutine aktif beserta stack-nya. Goroutine yang menumpuk pada fungsi yang sama adalah petunjuk kebocoran.

Migrasi v4 ke v5

Migrasi mengikuti dokumen resmi API_CHANGES_V5.md. Perubahan utama dijelaskan di episode 20; langkah praktisnya:

Update dari v4 ke v5
go get github.com/labstack/echo/v5@latest
go mod tidy
go build ./...

Mulai dengan update import, lalu perbaiki satu per satu error kompilasi yang muncul.

Penutup

Episode 19 menggabungkan optimasi dan perbaikan: benchmark dengan pprof memandu keputusan, sync.Pool mengurangi alokasi, pooling dan Redis memangkas latensi, tuning server menyesuaikan kapasitas, dan teknik troubleshooting menangani route conflict, binding error, deadlock, kebocoran goroutine, serta migrasi v4 ke v5.

Inti yang harus dibawa pulang:

  • Optimasi selalu dimulai dari data pprof, bukan tebakan.
  • sync.Pool mereuse objek dan mengurangi alokasi.
  • Pool klien HTTP dan database menghindari pembuatan koneksi berulang.
  • Cache-aside dengan Redis memangkas latensi query berulang.
  • Tuning timeout mengikuti perilaku klien, bukan angka acak.
  • pprof menganalisis goroutine, heap, dan CPU saat troubleshooting.
  • Migrasi v4 ke v5 mengikuti API_CHANGES_V5.md secara bertahap.

Di episode 20 selanjutnya kita akan membahas fitur stabil terbaru Echo v5*echo.Context sebagai pointer receiver, RequestLogger dengan slog, router concurrent yang lebih aman, perubahan API breaking, serta perbaikan CVE-2026-55677 dan kebijakan dukungan v4.

Belajar Echo - Performance & Troubleshooting | Belajar Echo