Paket 2 · Praktik LanjutanModul E — Performance, Cache & Application Infrastructure

Performance Engineering & Resource Management

Mengukur dan meningkatkan performa aplikasi: latency, throughput, profiling, load testing, dan alokasi resource.

Performa bukan sekadar “server cepat”. Ia adalah kemampuan memenuhi target latency dan throughput pada biaya yang wajar. Engineering performa dimulai dari pengukuran, bukan tebakan.

Metrik utama

MetrikArti
LatencyWaktu satu request
ThroughputRequest per detik
Error ratePersentase request gagal
SaturationSeberapa penuh resource
ApdexKepuasan pengguna berdasarkan latency

Gunakan persentil, bukan rata-rata:

  • p50 — median.
  • p95 — 95% request lebih cepat dari ini.
  • p99 — ekor latency; sering menunjukkan masalah.

Performance budget

Tentukan target sejak awal:

API p95 < 300 ms
Halaman utama p95 < 1.5 s
Error rate < 0.1%
CPU rata-rata < 70%

Tanpa target, optimasi tidak punya arah.

Bottleneck umum

LapisanBottleneck
ClientNetwork lambat, aset besar
ProxyTimeout, buffer, TLS
AppCPU, memory, event loop, query
DatabaseQuery lambat, lock, koneksi habis
CacheMiss rate tinggi, eviction
StorageIOPS, throughput
NetworkBandwidth, latency, packet loss

Node.js dan event loop

Node.js memakai event loop single-threaded. Operasi CPU-heavy memblokir semua request.

// Buruk: memblokir event loop
const hash = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512');

// Lebih baik: async
const hash = await pbkdf2(password, salt, 100000, 64, 'sha512');

Untuk beban CPU, gunakan worker thread, proses terpisah, atau PM2 cluster.

PM2 cluster

module.exports = {
  apps: [{
    name: 'app',
    script: 'server.js',
    instances: 'max',
    exec_mode: 'cluster',
  }],
};

Cluster memanfaatkan semua core, tetapi setiap proses punya memory dan koneksi database sendiri.

Resource limit

Docker Compose:

services:
  app:
    deploy:
      resources:
        limits:
          cpus: "1.5"
          memory: 512M
        reservations:
          memory: 256M

Systemd:

[Service]
MemoryMax=512M
CPUQuota=150%

Limit mencegah satu service menghabiskan host, tetapi terlalu ketat memicu OOM/restart.

Load testing

k6

import http from 'k6/http';
import { sleep, check } from 'k6';

export const options = {
  vus: 50,
  duration: '2m',
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(95)<500'],
  },
};

export default function () {
  const res = http.get('https://app.example.com/health');
  check(res, { 'status 200': (r) => r.status === 200 });
  sleep(1);
}
k6 run load-test.js

ab (ApacheBench)

ab -n 1000 -c 50 https://app.example.com/

Jangan melakukan load test terhadap produksi tanpa izin dan tanpa rencana.

Profiling

node --prof server.js
node --prof-process isolate-*.log > profile.txt

Untuk production, gunakan APM/OpenTelemetry untuk melihat span paling lambat.

Query database

EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42 ORDER BY created_at DESC LIMIT 20;

Perhatikan:

  • Sequential scan pada tabel besar.
  • Index yang tidak dipakai.
  • N+1 query.
  • Sorting dan join mahal.

Caching

Cache mengurangi beban database dan latency. Namun cache yang salah dapat menyajikan data basi.

const cached = await redis.get(key);
if (cached) return JSON.parse(cached);

const data = await db.query(...);
await redis.set(key, JSON.stringify(data), 'EX', 60);
return data;

Optimasi berurutan

  1. Ukur baseline.
  2. Temukan bottleneck terbesar.
  3. Perbaiki satu hal.
  4. Ukur ulang.
  5. Ulangi.

Optimasi prematur

Optimasi tanpa data sering menambah kompleksitas tanpa manfaat. Fokus pada bottleneck yang terukur dan berdampak pada pengguna.

Ringkasan

  • Ukur latency, throughput, error rate, dan saturation.
  • Gunakan p95/p99, bukan rata-rata.
  • Identifikasi bottleneck di app, database, cache, atau jaringan.
  • Load test dan profiling memandu optimasi.
  • Cache dan clustering membantu, tetapi bukan solusi semua masalah.

Selanjutnya

Tambahkan cache produksi di Caching & Redis untuk Production.

On this page