Episode 34 membahas scaling GraphQL: vertical scaling dengan optimasi resource dan memory, horizontal scaling dengan load balancing dan stateless design, scaling database dengan read replicas dan PgBouncer, caching berlapis, scaling WebSocket subscriptions dengan Redis PubSub, hingga circuit breaker dan bulkhead pattern.

Traffic kalian naik — dan pertanyaannya bukan "apakah server akan jebol", tapi "kapan dan bagaimana menanganinya". Episode 34 membahas scaling GraphQL: menambah kekuatan mesin, menambah jumlah mesin, dan memastikan seluruh komponen dari database sampai WebSocket ikut naik.
Kita akan membahas vertical scaling, horizontal scaling, scaling database, caching berlapis, scaling subscriptions, dan pola ketahanan seperti circuit breaker dan bulkhead.
Vertical scaling menambah resource pada satu mesin — cara termudah, tapi punya batas. Langkah yang masuk akal sebelum pindah ke horizontal:
{
"scripts": {
"start": "node --max-old-space-size=2048 dist/index.js"
}
}Optimasi lain: DataLoader batching (episode 9), caching (episode 19-20), dan pemangkasan query kompleks (episode 15) mengurangi beban per request sehingga satu mesin bisa melayani lebih banyak.
Horizontal scaling menambah jumlah instance di belakang load balancer:
client -> load balancer -> instance 1
-> instance 2
-> instance 3Syarat utama: server harus stateless — jangan simpan session atau cache di memori lokal instance. Semua state bersama diletakkan di Redis:
Jalankan beberapa instance dengan cluster pm2 start dist/index.js -i max.
Load balancer (nginx, ALB, atau Kubernetes Service) mendistribusikan request. Konsistensi diperoleh karena tidak ada state lokal yang harus dijaga sinkron.
Database sering menjadi bottleneck pertama. Strateginya:
docker run -d --name pgbouncer \
-e DB_HOST=db-primary -e DB_USER=app -e DB_PASSWORD=pass \
-p 6432:5432 edoburu/pgbouncerKoneksi aplikasi diarahkan ke PgBouncer (localhost:6432) sebagai ganti database langsung. Ini sangat penting di lingkungan serverless (episode 37) di mana koneksi dibuka tutup terus-menerus.
Cache di beberapa lapisan untuk memotong beban database:
Untuk invalidation di skala besar, gunakan pola event-based: mutation mem-publish event (episode 16) dan cache dihapus secara terpusat, bukan mengandalkan TTL semata.
Subscriptions yang melibatkan WebSocket membutuhkan perhatian khusus:
import { RedisPubSub } from "graphql-redis-subscriptions";
const pubsub = new RedisPubSub({
publisher: new Redis(process.env.REDIS_URL),
subscriber: new Redis(process.env.REDIS_URL),
});Koneksi WebSocket dikelola dengan graphql-ws (episode 16) di tiap instance; peristiwa dari mutation mana pun menyebar lewat Redis sehingga semua client menerimanya. Batasi juga jumlah koneksi per user dan gunakan heartbeat untuk membersihkan koneksi mati.
Di skala besar, kegagalan satu komponen jangan sampai melumpuhkan semuanya:
import { Pool } from "pg";
const userPool = new Pool({ connectionString: DB_URL, max: 10 });
const orderPool = new Pool({ connectionString: DB_URL, max: 5 });Pola-pola ketahanan ini akan kita perdalam di episode 35 bersama strategi high availability.
Inti yang harus dibawa pulang:
Di episode 35 selanjutnya kalian akan mempelajari disaster recovery dan high availability — desain multi-region dan failover, strategi backup dengan point-in-time recovery, perencanaan disaster recovery dengan RTO dan RPO, circuit breaker pattern, hingga graceful degradation dengan feature flags. API kalian akan tahan banting!