Belajar Performance Test Engineer - API & Database Performance
Episode 7 of 28

Belajar Performance Test Engineer - API & Database Performance

Menguji performa API endpoints secara spesifik — response time per endpoint, payload validation, dan error handling — serta mengidentifikasi database bottleneck: query latency, N+1 queries, connection pooling, dan indexing.

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

Pendahuluan

Setelah di episode 3-6 kita memahami berbagai genre testing (load, stress, soak, spike) dan tools (k6, JMeter, Locust), kini saatnya memperdalam testing ke area spesifik: API endpoints dan database performance. Di dunia modern, sebagian besar aplikasi berinteraksi lewat API, dan di balik setiap API ada database yang menyimpan dan mengambil data. Keduanya adalah titik bottleneck paling umum.

Episode ini membawa kalian dari menguji satu endpoint hingga memahami bagaimana database mempengaruhi performa API — dengan pendekatan terstruktur yang bisa langsung kalian praktikkan.

API Performance Testing

Menguji Satu Endpoint

Load testing API dimulai dari satu endpoint. Pastikan kalian menguji bukan hanya HTTP status, tetapi juga response body dan response time per endpoint — karena setiap endpoint punya karakteristik berbeda.

javascript
import http from 'k6/http';
import { check } from 'k6';
 
export const options = {
  vus: 50,
  duration: '2m',
};
 
export default function () {
  // GET products - read-heavy, harus cepat
  const products = http.get('https://api.example.com/products');
  check(products, {
    'products status 200': (r) => r.status === 200,
    'products has items': (r) => r.json().length > 0,
    'products < 200ms': (r) => r.timings.duration < 200,
  });
 
  // POST order - write-heavy, mungkin lebih lambat
  const order = http.post('https://api.example.com/orders', JSON.stringify({
    productId: 1,
    quantity: 2,
  }), { headers: { 'Content-Type': 'application/json' } });
  check(order, {
    'order status 201': (r) => r.status === 201,
    'order < 500ms': (r) => r.timings.duration < 500,
  });
}

Endpoint-Level Thresholds

Setiap endpoint punya karakteristik berbeda. Produk list mungkin harus di bawah 200ms, tetapi checkout mungkin boleh sampai 500ms. Buat thresholds per endpoint:

javascript
export const options = {
  thresholds: {
    'http_req_duration{endpoint:products}': ['p(95)<200'],
    'http_req_duration{endpoint:orders}': ['p(95)<500'],
    'http_req_duration{endpoint:search}': ['p(95)<300'],
  },
};

Menguji Payload

API performance bukan hanya tentang latency — tetapi juga tentang ukuran payload. Response yang terlalu besar memakan bandwidth dan memperlambat client-side rendering. Ukur ukuran response:

javascript
export default function () {
  const res = http.get('https://api.example.com/products');
  check(res, {
    'response size < 50KB': (r) => r.body.length < 50000,
    'status is 200': (r) => r.status === 200,
  });
  // Ukuran response mempengaruhi bandwidth dan client rendering
}

Database Performance

Mengidentifikasi Database Bottleneck

Database bottleneck paling sering muncul dalam tiga bentuk: query latency tinggi, N+1 queries, dan connection pool exhaustion. Performance test yang baik harus mengidentifikasi ketiganya.

Query Latency

Query latency adalah waktu yang dibutuhkan database untuk mengeksekusi satu query. Untuk mengukurnya, kita perlu menghubungkan response time API dengan query time database — biasanya lewat database profiling atau application performance monitoring (APM).

bash
# PostgreSQL: enable slow query logging
ALTER SYSTEM SET log_min_duration_statement = 200;  # Log query > 200ms
SELECT pg_reload_conf();
 
# Lihat slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

N+1 Queries

N+1 queries adalah anti-pattern di mana aplikasi menjalankan 1 query untuk mendapatkan N items, lalu 1 query lagi untuk setiap item — menghasilkan N+1 queries total. Di bawah load, ini menjadi bottleneck masif.

sql
-- Query pertama: ambil 100 products
SELECT * FROM products LIMIT 100;
 
-- N queries tambahan: ambil category untuk setiap product
SELECT * FROM categories WHERE id = 1;
SELECT * FROM categories WHERE id = 2;
-- ... 98 queries lagi

Cara mendeteksi: hitung jumlah query per request di APM. Jika 1 request ke /products menghasilkan 101 queries → N+1 problem.

Connection Pool

Connection pool adalah pool koneksi database yang dibagikan antar threads/requests. Jika pool terlalu kecil, request harus menunggu koneksi tersedia — menambah latency. Jika pool terlalu besar, database kehabisan connections.

javascript
// k6 test yang mengungkap connection pool issues
export const options = {
  vus: 200,  // 200 VUs = 200 concurrent connections
  duration: '2m',
};
 
export default function () {
  // Jika connection pool di aplikasi hanya 50,
  // 200 VUs akan menyebabkan waiting dan timeout
  const res = http.get('https://api.example.com/heavy-query');
  check(res, {
    'status 200': (r) => r.status === 200,
    'no timeout': (r) => r.timings.duration < 5000,
  });
}

Indexing

Index yang tidak ada atau tidak tepat adalah penyebab utama query lambat. Saat load test, query yang tadinya cepat di satu user bisa menjadi lambat di banyak concurrent users karena lock contention pada index.

sql
-- Cek index usage di PostgreSQL
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC
LIMIT 10;
 
-- Index yang tidak pernah dipakai = overhead write tanpa manfaat read

Menghubungkan API Test dengan Database Monitoring

Performance test yang powerful menggabungkan API-level testing dengan database-level monitoring. Saat menjalankan k6 test, pastikan kalian melihat:

  1. API response time (k6 output)
  2. Database query time (pg_stat_statements atau APM)
  3. System metrics (CPU, memory, disk I/O)

Jika API latency naik dari 100ms ke 500ms tetapi database query time tetap 10ms → bottleneck di aplikasi (CPU, serialization, atau external call), bukan di database. Jika database query time naik dari 10ms ke 200ms → bottleneck di database.

Connection Pool Testing

Pool Exhaustion Test

javascript
// Ramp-up agresif untuk menguji connection pool
export const options = {
  stages: [
    { duration: '1m', target: 50 },   // Normal
    { duration: '1m', target: 100 },  // Above pool size
    { duration: '2m', target: 100 },  // Steady-state above pool
    { duration: '1m', target: 200 },  // Far above pool
    { duration: '2m', target: 200 },  // Steady-state far above
    { duration: '1m', target: 0 },
  ],
};

Jika pool size = 50, maka di 100 VUs kalian akan melihat latency naik — ini menunjukkan request mulai menunggu koneksi. Di 200 VUs, error rate bisa melonjak jika timeout terlalu pendek.

Penutup

Di episode 7 ini kalian telah memahami API & database performance testing:

  • Menguji API endpoints dengan thresholds per endpoint — setiap endpoint punya karakteristik berbeda.
  • Database bottleneck: query latency, N+1 queries, connection pool exhaustion.
  • Menghubungkan API response time dengan database query time untuk menemukan akar masalah.
  • Connection pool testing: ramp-up agresif untuk mengungkap waiting dan timeout.

Di episode 8 selanjutnya, kita akan beralih ke sisi lain performa: Frontend & Web Performance — Core Web Vitals, Lighthouse, dan bagaimana menguji performa dari sisi client. Sampai jumpa di episode 8!

Belajar Performance Test Engineer - API & Database Performance | Belajar Performance Test Engineer