DEBI PRAHARADIKA
← Back to Blog Index
System Design2026-05-259 min read

Membangun Sistem Chat Real-Time: Short Polling, Long Polling, vs WebSockets

Panduan arsitektur sistem chat real-time yang membedakan Short Polling, Long Polling, dan WebSockets lengkap dengan sirkulasi siklus koneksi, diagram desain sistem, dan source code server-client.

Membangun aplikasi komunikasi interaktif (real-time chat) merupakan salah satu tantangan paling menarik dalam rekayasa perangkat lunak (Software Engineering). Protokol HTTP tradisional bersifat stateless dan menggunakan siklus dasar Request-Response yang diinisiasi eksklusif oleh sisi client. Server tidak dapat secara aktif mendorong (push) data ke client.

Untuk mensiasati keterbatasan ini, industri perangkat lunak mengembangkan tiga teknik utama: Short Polling, Long Polling, dan WebSockets.

Di dalam artikel ini, kita akan membongkar tuntas perbandingan ketiganya, menganalisis beban infrastruktur, melihat diagram desain sistemnya, serta mempelajari implementasi kode backend & frontend untuk masing-masing teknik.


Perbandingan Siklus Hidup Koneksi (Connection Lifecycle)

Berikut adalah cetak biru teknis perbandingan sirkulasi jaringan dari ketiga metode real-time tersebut:

Perbandingan Jaringan Polling vs WebSockets


1. Teknik Short Polling (HTTP Periodic Request)

Short Polling adalah teknik paling sederhana. Client secara periodik (misal setiap 2-5 detik) mengirimkan HTTP GET Request ke server untuk menanyakan "Apakah ada pesan baru?". Server akan langsung memeriksa database/cache dan segera merespon dengan data baru (jika ada) atau respon kosong.

Karakteristik:

  • Kelebihan: Sangat mudah diimplementasikan, bekerja di atas HTTP standar, tidak membutuhkan koneksi persisten yang menggantung di server.
  • Kekurangan: Sangat tidak efisien. Server akan kebanjiran request kosong (empty responses) yang memakan resource CPU, bandwidth, dan koneksi database secara sia-sia.

Implementasi Kode:

Sisi Server (Node.js & Express):

const express = require('express');
const app = express();

const messages = [
  { id: 1, text: "Halo!", sender: "Alice" }
];

// Endpoint untuk polling pesan
app.get('/api/messages', (req, res) => {
  const lastId = parseInt(req.query.lastId || 0);
  const newMessages = messages.filter(m => m.id > lastId);
  
  // Langsung merespon meskipun data kosong
  res.json({ messages: newMessages });
});

app.listen(3000, () => console.log('Short Polling server on port 3000'));

Sisi Client (Frontend React / Vanilla JS):

let lastMessageId = 1;

function startShortPolling() {
  setInterval(async () => {
    try {
      const response = await fetch(`/api/messages?lastId=${lastMessageId}`);
      const data = await response.json();
      
      if (data.messages.length > 0) {
        data.messages.forEach(msg => {
          console.log(`Pesan Baru: ${msg.text}`);
          lastMessageId = Math.max(lastMessageId, msg.id);
        });
      }
    } catch (error) {
      console.error("Polling gagal:", error);
    }
  }, 3000); // Polling secara periodik setiap 3 detik
}

2. Teknik Long Polling (HTTP Hanging Request)

Long Polling merupakan optimasi dari Short Polling. Client tetap mengirimkan HTTP Request, namun server tidak langsung merespon jika tidak ada data baru. Server akan "menahan" (hang) koneksi HTTP tersebut (biasanya menggunakan timeout 20-30 detik) hingga ada data baru masuk. Begitu ada data baru atau waktu timeout tercapai, server merespon. Client yang menerima respon akan segera membuka request baru lagi.

Karakteristik:

  • Kelebihan: Mengurangi jumlah request kosong secara signifikan dibanding Short Polling. Latensi penerimaan data jauh lebih rendah.
  • Kekurangan: Server harus mampu menahan ribuan koneksi terbuka (open connections), yang dapat memakan memori RAM server jika tidak dikonfigurasi secara asynchronous.

Implementasi Kode:

Sisi Server (Node.js & Express):

const express = require('express');
const app = express();

const clients = [];
const messages = [];

app.get('/api/messages/subscribe', (req, res) => {
  const lastId = parseInt(req.query.lastId || 0);
  const newMessages = messages.filter(m => m.id > lastId);

  if (newMessages.length > 0) {
    return res.json({ messages: newMessages });
  }

  // Jika tidak ada data baru, simpan response object ke array untuk ditangguhkan
  clients.push(res);

  // Set timeout keamanan agar request tidak menggantung selamanya
  req.on('close', () => {
    const idx = clients.indexOf(res);
    if (idx !== -1) clients.splice(idx, 1);
  });
});

// Endpoint untuk mengirim pesan (pemicu push)
app.post('/api/messages', express.json(), (req, res) => {
  const newMessage = { id: messages.length + 1, text: req.body.text };
  messages.push(newMessage);

  // Broadcast langsung ke semua client yang sedang menggantung
  while (clients.length > 0) {
    const clientRes = clients.shift();
    clientRes.json({ messages: [newMessage] });
  }

  res.status(201).json({ success: true });
});

app.listen(3000, () => console.log('Long Polling server on port 3000'));

Sisi Client (Frontend React / Vanilla JS):

let lastMessageId = 0;

async function startLongPolling() {
  try {
    const response = await fetch(`/api/messages/subscribe?lastId=${lastMessageId}`);
    
    if (response.status === 200) {
      const data = await response.json();
      
      data.messages.forEach(msg => {
        console.log(`Pesan Baru (Long Poll): ${msg.text}`);
        lastMessageId = Math.max(lastMessageId, msg.id);
      });
    }
  } catch (error) {
    console.error("Koneksi terputus, mencoba lagi dalam 5 detik...");
    await new Promise(resolve => setTimeout(resolve, 5000));
  } finally {
    // Rekursif: Langsung buka request baru setelah menerima respon
    startLongPolling();
  }
}

3. Teknik WebSocket (Full-Duplex TCP Connection)

WebSocket adalah protokol komunikasi dua arah (full-duplex) berlatensi sangat rendah. Berbeda dengan polling yang menggunakan HTTP berulang, WebSocket menggunakan satu handshake HTTP awal untuk menaikkan kelas koneksi (Upgrade) menjadi koneksi TCP persisten yang permanen antara client dan server.

Setelah koneksi terjalin, baik client maupun server dapat saling berkirim paket data (Data Frame) kapan saja secara langsung tanpa overhead header HTTP.

Karakteristik:

  • Kelebihan: Sangat hemat bandwidth (overhead header hanya ~2 byte per frame), latensi mendekati instan (real-time murni), mendukung aliran data dua arah sejati (bi-directional).
  • Kekurangan: Lebih kompleks dalam load balancing, memerlukan penanganan khusus jika koneksi drop (reconnection logic), dan server harus memelihara state koneksi aktif (stateful).

Implementasi Kode:

Sisi Server (Node.js & Library ws):

const { WebSocketServer } = require('ws');
const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client baru terhubung via WebSocket!');

  ws.on('message', (message) => {
    const parsedData = JSON.parse(message);
    console.log(`Diterima: ${parsedData.text}`);

    // Broadcast pesan ke semua client yang aktif terhubung
    wss.clients.forEach((client) => {
      if (client.readyState === 1) { // 1 = OPEN
        client.send(JSON.stringify({
          sender: "System",
          text: parsedData.text,
          time: new Date().toLocaleTimeString()
        }));
      }
    });
  });

  ws.on('close', () => console.log('Client terputus.'));
});

console.log('WebSocket server berjalan di port 8080');

Sisi Client (Frontend React / Vanilla JS):

let socket;

function connectWebSocket() {
  socket = new WebSocket("ws://localhost:8080");

  socket.onopen = () => {
    console.log("Koneksi WebSocket berhasil terjalin!");
    // Mengirim pesan contoh
    socket.send(JSON.stringify({ text: "Halo server!" }));
  };

  socket.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log(`Pesan dari server: [${data.sender}] ${data.text}`);
  };

  socket.onclose = () => {
    console.log("Koneksi ditutup. Mencoba menghubungkan kembali...");
    setTimeout(connectWebSocket, 3000); // Auto reconnect logic
  };

  socket.onerror = (error) => {
    console.error("WebSocket Error:", error);
    socket.close();
  };
}

Desain Sistem Skala Besar (System Thinking & Architecture)

Pada implementasi skala produksi dengan jutaan pengguna aktif (concurrent users), sebuah server tunggal tidak akan mampu menahan semua koneksi WebSocket. Kita harus membagi beban secara horizontal (horizontal scaling).

Berikut adalah desain arsitektur berskala besar menggunakan kombinasi Load Balancer, WebSocket Cluster, dan Redis Pub/Sub Connection Plane:

Desain Sistem WebSocket Skala Besar

Alur System Thinking Kerja Arsitektur:

  1. Load Balancer (Nginx / HAProxy): Menerima koneksi WebSocket dari ribuan klien dan mendistribusikannya secara merata ke klaster instance server Node.js menggunakan algoritma IP Hash atau least connections. Load balancer wajib dikonfigurasi dengan session affinity (sticky session) agar handshake HTTP Upgrade berhasil diarahkan ke server yang sama.
  2. Klaster Server WebSocket: Terdiri dari beberapa instance server independen. Jika Client A terhubung ke Instance 1 dan Client B terhubung ke Instance 2, mereka tidak dapat langsung saling berkirim pesan karena beda server memory space.
  3. Redis Pub/Sub Connection Plane: Sebagai penengah (message broker). Ketika Instance 1 menerima pesan chat dari Client A yang ditujukan untuk Client B, Instance 1 akan menerbitkan (publish) pesan tersebut ke saluran Redis Pub/Sub. Semua instance server lain yang berlangganan (subscribe) saluran tersebut akan menerima pesan itu secara real-time. Instance 2 kemudian meneruskannya langsung ke Client B yang terhubung di memorinya.
  4. Database Relasional (PostgreSQL): Digunakan untuk mencatat message history, otentikasi user, dan data relasional berkeandalan tinggi secara asinkron (menggunakan antrean kerja / message queue agar proses database write tidak menahan koneksi real-time WebSocket).

Kesimpulan: Kapan Harus Menggunakan Apa?

  • Gunakan Short Polling hanya jika Anda sedang membangun prototipe cepat (MVP) yang sangat jarang memperbarui data (seperti grafik analitik dashboard harian yang tidak butuh instan).
  • Gunakan Long Polling jika Anda membutuhkan responsivitas tinggi tetapi infrastruktur Anda berada di bawah batasan firewall ketat yang memblokir protokol non-HTTP standar.
  • Gunakan WebSockets untuk aplikasi real-time sejati seperti chat interaktif, multiplayer gaming, kolaborasi dokumen (seperti Figma/Google Docs), dan monitoring metrik server instan demi menjaga kestabilan latensi dan efisiensi bandwidth yang maksimal.