AizuDemy

Tutorial Continuous Profiling Backend Go Pakai eBPF Pyroscope di VPS

Tutorial Continuous Profiling Backend Go Pakai eBPF Pyroscope di VPS
๐ŸŽง
Dengarkan Artikel Ini
Suara AI Otomatis โ€ข 6 mnt baca baca
โšก TL;DR

Poin Kunci Artikel Ini:

  • VPS Linux dengan Kernel versi 4.19 atau lebih baru (Ubuntu 22.04 LTS direkomendasikan).
  • Akses root atau hak akses sudoer pada VPS.
  • Docker Engine v20.10+ dan Docker Compose v2+.
๐Ÿ“‹ Daftar Isi Materi Tutup โ–ด

Latar Belakang: Masalah CPU Spike dan Memory Leak di Production

Aplikasi backend Go miliki efisiensi tinggi. Masalah performa tetap muncul lingkungan production. CPU spike mendadak picu high latency. Memory leak perlahan picu Out Of Memory (OOM) Killer kernel Linux matikan proses service. Metrics Prometheus catat tren kenaikan resource. Log aplikasi rekam pesan error. Log dan metrics gagal tunjukkan baris kode spesifik penyebab utama masalah.

Profiling konvensional Go pakai package net/http/pprof miliki keterbatasan teknis. Pprof butuh ekspos HTTP endpoint internal. Pprof butuh ubah kode aplikasi. Pprof butuh pemicu manual saat insiden berlangsung. Profiling manual sering lewatkan insiden transient yang terjadi acak. Profiling pprof pada sampel durasi panjang tambah overhead latensi aplikasi akibat kalkulasi garbage collection pause.

Solusi komprehensif: Continuous Profiling pakai eBPF (Extended Berkeley Packet Filter) dan Grafana Pyroscope. eBPF jalankan bytecode khusus langsung di dalam Linux Kernel Space. Agent eBPF hook subsystem perf_events Linux. Agent amati eksekusi fungsi tanpa ubah kode Go. Agent kumpulkan stack trace otomatis via kernel ring buffer. Overhead CPU di bawah 1%. Biner aplikasi Go di-profile kontinu 24/7 di VPS production tanpa penghentian service.

Persiapan Kernel Linux dan Environment VPS

Persyaratan sistem minimum jalankan eBPF Pyroscope profiling:

  • VPS Linux dengan Kernel versi 4.19 atau lebih baru (Ubuntu 22.04 LTS direkomendasikan).
  • Akses root atau hak akses sudoer pada VPS.
  • Docker Engine v20.10+ dan Docker Compose v2+.
  • Go Compiler toolchain v1.20+.
  • Biner aplikasi Go dikompilasi tanpa membuang simbol debug. Pembatas: jangan gunakan flag -ldflags="-s -w". Flag -s menghapus symbol table. Flag -w menghapus DWARF debug information. eBPF butuh DWARF info untuk memetakan alamat memori ke nama fungsi dan nomor baris kode Go.

1. Konfigurasi Parameter Sysctl Kernel

eBPF butuh izin akses subsystem perf_events Linux. Eksekusi perintah sysctl berikut pada terminal VPS:

sudo sysctl -w kernel.perf_event_paranoid=-1
sudo sysctl -w kernel.kptr_restrict=0

Nilai kernel.perf_event_paranoid=-1 izinkan agen eBPF baca hardware performance counters tanpa proteksi terbatas. Nilai kernel.kptr_restrict=0 izinkan pembacaan alamat pointer simbol kernel Linux.

2. Deploy Server Grafana Pyroscope

Buat direktori proyek pyroscope-server dan simpan konfigurasi docker-compose.yml berikut:

version: '3.8'

services:
  pyroscope:
    image: pyroscope/pyroscope:latest
    container_name: pyroscope-server
    ports:
      - "4040:4040"
    command:
      - "server"
    volumes:
      - pyroscope-data:/var/lib/pyroscope
    restart: always

volumes:
  pyroscope-data:

Jalankan container Pyroscope Server pakai Docker Compose:

docker compose up -d

Verifikasi status kontainer berjalan. Akses Pyroscope Web UI lewat browser pada alamat http://<IP-VPS-ANDA>:4040.

3. Buat Aplikasi Go Target Profiling

Buat file main.go berisi kode simulasi beban kalkulasi CPU dan alokasi memori berlebih:

package main

import (
	"crypto/sha256"
	"fmt"
	"net/http"
	"sync"
	"time"
)

func cpuHeavyTask() {
	for i := 0; i < 200000; i++ {
		_ = sha256.Sum256([]byte(fmt.Sprintf("payload-data-%d-%d", i, time.Now().UnixNano())))
	}
}

func memoryLeakTask() {
	var leak [][]byte
	for i := 0; i < 1000; i++ {
		data := make([]byte, 1024*1024) // Alokasi 1MB
		leak = append(leak, data)
	}
}

func taskHandler(w http.ResponseWriter, r *http.Request) {
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		cpuHeavyTask()
	}()
	go func() {
		defer wg.Done()
		memoryLeakTask()
	}()
	wg.Wait()
	w.Write([]byte("Execution Finished"))
}

func main() {
	http.HandleFunc("/work", taskHandler)
	fmt.Println("Target Go App running on port :8080")
	http.ListenAndServe(":8080", nil)
}

Kompilasi source code Go tanpa membuang simbol tabel:

go build -o go-app main.go
./go-app &

4. Jalankan Pyroscope eBPF Agent

Unduh dan jalankan Pyroscope eBPF agent pakai hak akses root. Agent lacak seluruh binary biner pada host Linux:

sudo pyroscope ebpf --application-name go-backend-prod --server-address http://localhost:4040

Agent eBPF pasang probe pada kernel scheduler. Sample stack trace dikirim periodik ke Pyroscope Server tiap 99 Hz (99 kali per detik).

Analisis Flamegraph dan Troubleshooting Bottleneck Kode

Kirim traffic uji beban tinggi ke server aplikasi Go pakai tool hey:

hey -n 2000 -c 20 http://localhost:8080/work

Komponen Utama Flamegraph Pyroscope

Buka UI Pyroscope pada alamat http://<IP-VPS-ANDA>:4040. Pilih aplikasi go-backend-prod.

  • Sumbu Horizontal (X): Tunjukkan persentase total waktu CPU atau alokasi memori relatif. Semakin lebar kotak fungsi, semakin besar konsumsi sumber daya. Urutan horisontal bukan urutan waktu eksekusi.
  • Sumbu Vertikal (Y): Tunjukkan kedalaman call stack. Fungsi dasar berada di bawah. Fungsi anak yang dipanggil berada di atas.
  • Frame Hotspot: Frame fungsi teratas yang lebar tanpa anak fungsi di atasnya merupakan hotspot penyebab utama penggunaan resource.

1. Troubleshooting CPU Bottleneck

Pilih tipe profile process_cpu:cpu pada dropdown menu dashboard Pyroscope. Amati frame terlebar pada posisi stack paling atas.

Hasil profiling tunjukkan fungsi crypto/sha256.Sum256 habiskan konsumsi durasi CPU dominan. Fungsi cpuHeavyTask() mendominasi total sampel CPU. Pembentukan string berulang lewat fmt.Sprintf di dalam loop perbesar alokasi CPU dan garbage collection overhead.

Solusi optimasi: Hindari formatting string berulang di dalam loop kritis. Pakai library hashing non-kriptografi efisien seperti xxhash jika kebutuhan sistem tidak memerlukan enkripsi aman.

2. Troubleshooting Memory Leak

Ubah tipe profile ke memory:alloc_space atau memory:inuse_space pada dashboard.

Flamegraph tunjukkan fungsi memoryLeakTask() lakukan alokasi slice byte berulang lewat make([]byte, 1024*1024). Memori heap melonjak tajam tiap kali handler HTTP diproses.

Solusi optimasi: Terapkan Object Pooling pakai sync.Pool untuk gunakan ulang buffer memori yang sudah dialokasikan.

var byteBufferPool = sync.Pool{
	New: func() interface{} {
		b := make([]byte, 1024*1024)
		return &b
	},
}

func memoryOptimizedTask() {
	bufPtr := byteBufferPool.Get().(*[]byte)
	defer byteBufferPool.Put(bufPtr)
	// Gunakan buffer tanpa alokasi heap baru
}

Checklist Langkah Troubleshooting Continuous Profiling

Ikuti urutan langkah standar berikut untuk mengisolasi dan memperbaiki insiden performa di VPS production:

  1. Pantau alert latensi atau grafik lonjakan CPU pada sistem pemantauan VPS.
  2. Buka dashboard Grafana Pyroscope pada URL http://<IP-VPS-ANDA>:4040.
  3. Atur rentang waktu (time-range selector) tepat pada periode lonjakan insiden terjadi.
  4. Pilih tipe profil process_cpu:cpu jika masalah terkait dengan High CPU usage atau response time lambat.
  5. Pilih tipe profil memory:inuse_space jika masalah terkait dengan memory leak atau OOM crash.
  6. Cari kotak fungsi terlebar (hotspot) di bagian atas Flamegraph.
  7. Klik pada kotak fungsi tersebut untuk memeriksa nama paket, file source, dan nomor baris kode presisi.
  8. Buka source code aplikasi Go pada environment lokal, lalu lakukan refactoring kode berdasarkan temuan hotspot.
  9. Kompilasi ulang biner Go tanpa flag -s -w dan jalankan kembali deployment ke VPS.
  10. Gunakan fitur Diff View pada Pyroscope untuk membandingkan data Flamegraph sebelum dan sesudah perbaikan guna memastikan penurunan alokasi resource.

Kesimpulan & Best Practice Continuous Profiling

eBPF Pyroscope berikan visibilitas runtime Go tingkat kernel tanpa modifikasi kode aplikasi. Pengumpulan profil berjalan otomatis tanpa ganggu stabilitas sistem VPS production.

Best Practice Production Deployment:

  • Pertahankan Debug Symbols: Jangan tambahkan flag -s -w pada perintah go build agar nama fungsi dan baris kode terbaca jelas di Flamegraph.
  • Set Sampling Frequency Safe: Gunakan nilai standar 99 Hz pada agen eBPF untuk batasi overhead CPU di bawah 1%.
  • Gunakan Diff View: Bandingkan Flamegraph antar versi rilis sebelum dan sesudah deployment untuk deteksi dini regresi performa.
  • Atur Retention Policy Data: Konfigurasi retensi data pada server Pyroscope sesuai kapasitas media simpan VPS agar disk tidak habis.

๐Ÿ“– Artikel Terkait