NodeJS Performance Tuning untuk High Traffic: Menangani Ribuan Request per Detik

NodeJS Performance Tuning untuk High Traffic: Menangani Ribuan Request per Detik

NodeJS sering dipilih untuk aplikasi dengan trafik tinggi karena kemampuannya menangani ribuan koneksi secara simultan.

Namun di dunia nyata, banyak aplikasi NodeJS gagal saat traffic meningkat, bukan karena NodeJS lemah, melainkan karena salah desain, salah konfigurasi, dan kurang tuning performance.

Masalah yang sering muncul:

  • API tiba-tiba lambat saat traffic naik
  • CPU 100% padahal request ringan
  • Memory naik terus (memory leak)
  • Aplikasi crash saat peak hour
  • Scaling tidak memberikan dampak signifikan

Artikel ini akan membahas NodeJS performance tuning untuk high traffic secara menyeluruh, mulai dari level kode, runtime, database, network, hingga arsitektur, lengkap dengan contoh nyata yang benar-benar digunakan di production.


1. Memahami Batasan NodeJS di High Traffic

1.1 Single Thread & Event Loop

NodeJS menggunakan:

  • Single main thread
  • Event loop non-blocking

Artinya:

  • Sangat cepat untuk I/O (API, DB, network)
  • Sangat buruk untuk CPU-heavy task

High traffic ≠ CPU heavy.
High traffic = banyak request kecil dalam waktu bersamaan.


1.2 Contoh Kesalahan Fatal di High Traffic

app.get('/calculate', (req, res) => {
  const result = heavyCalculation(); // blocking
  res.json(result);
});

Dampak di production:

  • Semua request lain ikut tertunda
  • Event loop macet
  • Latency melonjak tajam

2. Cluster Mode: Menggunakan Semua Core CPU

2.1 Masalah Default NodeJS

Secara default:

node app.js

➡️ Hanya 1 core CPU yang digunakan.


2.2 Solusi: PM2 Cluster Mode

pm2 start app.js -i max

PM2 akan:

  • Menjalankan app di semua core
  • Membagi traffic otomatis
  • Restart process jika crash

📈 Dampak nyata di production:

  • Throughput naik 2–4x
  • CPU lebih stabil
  • Downtime menurun drastis

3. Hindari Event Loop Blocking (WAJIB)

3.1 Contoh Blocking Code

function processData(data) {
  for (let i = 0; i < 1e9; i++) {}
  return data;
}

Satu request = seluruh server lambat.


3.2 Solusi 1: Worker Threads

const { Worker } = require('worker_threads');

app.get('/report', (req, res) => {
  const worker = new Worker('./worker.js');
  worker.on('message', data => res.json(data));
});

3.3 Solusi 2: Pisahkan ke Service Lain

Best practice SaaS:

  • NodeJS → API
  • Go / Python → heavy processing
  • Komunikasi via queue

4. Database Performance Tuning

4.1 Kesalahan Umum: Koneksi per Request

app.get('/users', async () => {
  const conn = await mysql.createConnection(config);
  return conn.query('SELECT * FROM users');
});

❌ Lambat
❌ Tidak scalable


4.2 Solusi: Connection Pooling

const pool = mysql.createPool({
  connectionLimit: 20,
  host: 'localhost',
  user: 'app'
});

app.get('/users', async () => {
  const [rows] = await pool.query(
    'SELECT id, name FROM users LIMIT 50'
  );
  return rows;
});

📉 Efek nyata:

  • Latency turun drastis
  • DB tidak overload saat traffic tinggi

4.3 Index Database Itu Lebih Penting dari NodeJS

90% bottleneck high traffic = database.

Pastikan:

  • Index kolom WHERE
  • Index foreign key
  • Hindari SELECT *

5. Cache Strategy untuk High Traffic

5.1 Tanpa Cache (Masalah Besar)

app.get('/stats', async (req, res) => {
  const data = await db.getStats();
  res.json(data);
});

Setiap request = query mahal.


5.2 Redis Cache (Solusi Production)

app.get('/stats', async (req, res) => {
  const cached = await redis.get('stats');
  if (cached) {
    return res.json(JSON.parse(cached));
  }

  const data = await db.getStats();
  await redis.setex('stats', 60, JSON.stringify(data));
  res.json(data);
});

📊 Hasil nyata:

  • DB load turun 70–90%
  • API stabil saat spike traffic

5.3 Multi-Level Cache

  1. CDN (Cloudflare)
  2. Nginx
  3. Redis
  4. In-memory

6. HTTP & Network Optimization

6.1 Aktifkan Keep-Alive

Tanpa keep-alive:

  • Handshake berulang
  • Latency naik

Dengan Nginx:

keepalive_timeout 65;

6.2 Compression

Gunakan:

  • gzip
  • brotli

Payload kecil = throughput besar.


7. Memory Management & Leak Prevention

7.1 Gejala Memory Leak

  • RAM naik terus
  • Tidak turun meski traffic turun
  • PM2 restart berulang

7.2 Contoh Penyebab Leak

const cache = [];

app.get('/data', (req, res) => {
  cache.push(req.body);
  res.send('ok');
});

7.3 Atur Memory Limit

node --max-old-space-size=4096 app.js

Dengan PM2:

pm2 start app.js --max-memory-restart 2G

8. Logging Aman untuk High Traffic

8.1 Anti-Pattern Logging

fs.writeFileSync('log.txt', data);

❌ Blocking
❌ Slow


8.2 Logging Asynchronous

const pino = require('pino')();

pino.info({
  userId,
  action: 'login'
});

9. Rate Limiting & Load Protection

9.1 Rate Limit API

const rateLimit = require('express-rate-limit');

app.use(rateLimit({
  windowMs: 60 * 1000,
  max: 100
}));

Melindungi dari:

  • Abuse
  • Bot
  • Traffic spike tidak wajar

9.2 Load Shedding

Saat overload:

  • Tolak request non-kritis
  • Prioritaskan core business API

10. Graceful Shutdown (Sangat Penting)

10.1 Tanpa Graceful Shutdown

  • Request terputus
  • Data inconsistency

10.2 Implementasi Benar

const server = app.listen(3000);

process.on('SIGTERM', () => {
  console.log('Shutting down...');
  server.close(() => {
    process.exit(0);
  });
});

11. Payload Optimization

11.1 Overfetching (Salah)

{
  "id": 1,
  "name": "User",
  "created_at": "...",
  "updated_at": "...",
  "preferences": {}
}

11.2 Payload Minimal (Benar)

{
  "id": 1,
  "name": "User"
}

📉 Payload kecil → throughput besar.


12. Load Testing (WAJIB Sebelum Production)

12.1 Contoh Load Test dengan Autocannon

npx autocannon -c 500 -d 30 https://api.domain.com

Pantau:

  • Latency p95
  • Error rate
  • Requests/sec

13. Studi Kasus Nyata

Kondisi Awal

  • NodeJS API
  • 2.000 req/detik
  • Latency 1.8s
  • CPU 90%

Optimasi

  • PM2 cluster
  • Redis cache
  • DB pooling
  • Rate limit
  • Payload trimming

Hasil

  • Latency < 200ms
  • CPU stabil 50%
  • Zero downtime saat peak

14. Checklist Production High Traffic

✅ NodeJS LTS
✅ Cluster mode
✅ Redis cache
✅ DB pooling
✅ Async logging
✅ Rate limit
✅ Graceful shutdown
✅ Load testing


Kesimpulan

NodeJS sangat mampu menangani high traffic, tetapi hanya jika diperlakukan sebagai sistem production yang serius.

Masalah performa hampir selalu disebabkan oleh:

  • Event loop blocking
  • Salah desain database
  • Tidak ada cache
  • Tidak ada monitoring

High traffic bukan soal framework, tapi disiplin engineering.