Go vs Node.js Load-Testing Benchmark
Studi throughput & latency terkontrol dengan k6
- 712,788
- Request
- 16
- Eksekusi
- 0.00%
- Kegagalan HTTP
Ringkasan
Benchmark terkontrol yang membandingkan backend Go dan Node.js di balik endpoint, database, dan cache yang identik. Tujuannya bukan mencari pemenang, melainkan melihat bagaimana selisih performanya bergeser saat beban naik lima kali lipat.
Kedua stack dibebani pada dua tingkat konkurensi - 20 dan 100 virtual user - terhadap empat endpoint yang dipilih untuk mengisolasi perilaku CPU, database, dan cache. Di seluruh endpoint dan kedua tingkat beban, Go unggul pada throughput sebesar 1,19× sampai 1,65×, dan urutannya tidak pernah berbalik.
Tujuan
Mengukur throughput dan latency layanan Go dan Node.js yang setara dalam kondisi identik, lalu mengamati bagaimana selisihnya berubah saat beban naik dari 20 ke 100 virtual user.
Desain benchmark
- 4 endpoint × 2 stack × 2 tingkat beban = 16 eksekusi.
- Satu PostgreSQL 16 (10.000 baris) dan Redis 7 yang dipakai bersama - satu instance untuk kedua stack, supaya tidak ada yang dapat lingkungan lebih menguntungkan.
- SQL yang identik (sama persis karakter demi karakter), LIMIT 100, DB pool 25, Redis pool 25, serta cache key & TTL yang sama di kedua sisi.
- Script k6 yang sama menjalankan semua kombinasi; tingkat beban diatur lewat environment variable, bukan dengan mengubah isi file.
- Executor constant-vus, 30 detik per eksekusi, dengan threshold p95 < 500 ms, http_req_failed < 1%, dan checks > 99%.
Cakupan pengujian
Endpoint yang diuji
- /hello - murni CPU, tanpa I/O (baseline penanganan HTTP)
- /products - query database ringan (LIMIT 100)
- /products-where-like - LIKE dengan sequential scan (tidak bisa diindeks)
- /products-with-cache - cache-aside Redis
Tingkat beban
- 20 VU - karakter beban kerja masih mendominasi selisihnya
- 100 VU - selisih antar endpoint menyempit ke 1,19×–1,29× saat resource bersama jenuh
Strategi pengujian
- Executor constant-vus, eksekusi 30 detik pada 20 dan 100 VU.
- Threshold ditegakkan oleh k6: p95 < 500 ms, http_req_failed < 1%, checks > 99%.
- Kesetaraan payload diverifikasi dalam byte absolut supaya response yang lebih kecil tidak memalsukan kemenangan kecepatan.
- Check k6 memvalidasi isi body (count === 100) dan header cache X-Cache: HIT, bukan cuma status 200.
- Key Redis dihapus sebelum tiap eksekusi cache supaya TTL sisa tidak mencemari hasil.
Integritas pengukuran
Pada 100 VU, Node secara tidak terduga mencatat p95 latency lebih rendah daripada Go di kedua endpoint database. Sebelum menganggapnya sebagai hasil, saya memeriksa ke mana waktunya habis: pada /products, bagian request di luar server (p95 total dikurangi waktu tunggu di sisi server) sekitar 34 ms untuk Go berbanding sekitar 1,27 ms untuk Node - hampir 27×. Selisih data terkirim sebesar 27% (258 MB vs 203 MB) tidak bisa menjelaskan selisih waktu 27×, sehingga penyebabnya lebih mengarah ke load generator, bukan ke aplikasinya. Karena k6 dan kedua aplikasi berbagi satu laptop 8 GB, temuan itu saya tahan dulu sampai bisa diulang dengan load generator di mesin terpisah.
Arsitektur
- k6 (container)beban constant-vus
- go-api / node-apiendpoint identik
- PostgreSQL 16dipakai bersama, 10.000 baris
- Redis 7cache-aside bersama
Implementasi
export const options = {
scenarios: { load: { executor: 'constant-vus', vus: 100, duration: '30s' } },
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
checks: ['rate>0.99'],
},
};
export default function () {
const res = http.get(`${BASE_URL}/products`);
check(res, {
'status 200': (r) => r.status === 200,
'got 100 products': (r) => r.json().count === 100,
});
}docker run --rm -i --network bench \
-v "$PWD/k6:/scripts" grafana/k6 run \
-e BASE_URL=http://go-api:8080 -e STACK=go -e VUS=100 \
/scripts/scenarios/products.jspostgres:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U benchuser -d benchdb"]
interval: 5s
timeout: 3s
retries: 10
go-api:
build: ./go-api
depends_on:
postgres: { condition: service_healthy }docker exec bench-redis redis-cli DEL products:top100Hasil - throughput
20 VU
/hello
/products
/products-where-like
/products-with-cache
100 VU
/hello
/products
/products-where-like
/products-with-cache
Request per detik per endpoint, Go vs Node.js. Go unggul pada throughput di semua endpoint dan kedua tingkat beban. Sumber: k6/results/*.json.
Hasil
712,788
Request
dari 16 eksekusi
0.00%
Kegagalan HTTP
100%
Check fungsional lolos
1.19–1.65×
Keunggulan throughput Go
413.36 ms
p95 tertinggi
di bawah threshold 500 ms