Anomali HTTP Polling: Overhead Dan Pemborosan Resource
Pada awal era pengembangan web, mengimplementasikan interaksi interaktif dilakukan dengan mengirimkan permintaan HTTP secara berkala dari peramban ke server setiap beberapa detik (Short Polling). Meskipun secara sepintas terlihat berhasil, pendekatan ini menyimpan cacat arsitektur yang sangat merugikan ketika aplikasi berkembang pesat.
Setiap kali peramban melakukan request polling, koneksi HTTP baru atau reused connection harus membawa seluruh payload header HTTP. Informasi seperti User-Agent, Cookie session, token autentikasi Authorization: Bearer, serta metadata routing menghasilkan overhead antara 1 KB hingga 2 KB per permintaan. Jika data yang diperbarui hanya berukuran 15 byte JSON, maka lebih dari 98 persen bandwidth jaringan terbuang hanya untuk mengirimkan header.
"Melakukan HTTP Polling untuk memperbarui UI realtime ibarat mengetuk pintu rumah tetangga Anda setiap dua detik untuk bertanya apakah ada surat masuk. Protokol WebSocket menyediakan pintu terbuka yang memberi tahu Anda tepat ketika surat itu tiba."
MAYASTRA NAWALOKA, Realtime Systems Engineer
Dampak Pada CPU Server Dan Database Load
Kerugian terbesar dari HTTP Polling tidak hanya terletak pada konsumsi bandwidth jaringan, melainkan pada beban kerja pemrosesan server dan basis data. Ketika 10.000 pengguna aktif melakukan polling setiap 3 detik, server akan menerima sekitar 3.333 request per detik (RPS).
Sebagian besar dari permintaan tersebut (sering kali mencapai 95+ persen) mengembalikan respon kosong 304 Not Modified atau 200 OK dengan array kosong karena tidak ada perubahan data baru. Walaupun data tidak berubah, server tetap mengeksekusi kueri basis data, membuang alokasi thread CPU, dan menghabiskan connection pool.
Perbandingan Protokol: Polling vs SSE vs WebSocket
Untuk memahami karakteristik performa secara menyeluruh, berikut adalah perbandingan teknis antara empat opsi komunikasi pada aplikasi web:
| Kriteria Protokol | HTTP Short Polling | HTTP Long Polling | Server-Sent Events (SSE) | WebSocket |
|---|---|---|---|---|
| Model Komunikasi | Unidirectional Client-to-Server | Simulated Push via Hold Connection | Unidirectional Server-to-Client | Full-Duplex Bi-Directional |
| Overhead Header | Tinggi (1-2 KB per request) | Tinggi pada setiap reconnect | Minimal (Text/Event-Stream) | Sangat Rendah (2-10 Byte Frame) |
| Multiplexing / Re-use | Tidak (Koneksi Baru/HTTP Keep-Alive) | Tidak (Satu request per event) | Ya (Koneksi TCP Tunggal Persistence) | Ya (Persistent Full-Duplex TCP) |
| Efisiensi CPU Server | Sangat Rendah (High CPU Spikes) | Sedang (Thread Idle Overhead) | Sangat Tinggi (Async Streaming) | Maksimal (Event-Loop Non-Blocking) |
| Kasus Penggunaan Ideal | Legacy System Batch Update | Fallback untuk Firewall Ketat | Stock Ticker, Live Dashboard, News Feed | Chat Application, Collaborative Edit, Gaming |
Solusi Modern: Bi-Directional WebSocket & SSE Streaming
Protokol WebSocket memulainya melalui koneksi HTTP standar, yang kemudian ditingkatkan (upgraded) via HTTP 101 Switching Protocols menjadi koneksi TCP persisten full-duplex. Setelah pertukaran handshake selesai, data dikirim dalam bentuk frame biner atau teks yang berukuran sekecil 2 byte saja.
// Contoh Arsitektur WebSocket Connection Pool (Go Engine)
package main
import (
"sync"
"github.com/gorilla/websocket"
)
type ClientManager struct {
clients map[*websocket.Conn]bool
broadcast chan []byte
register chan *websocket.Conn
unregister chan *websocket.Conn
mutex sync.RWMutex
}
func (manager *ClientManager) Start() {
for {
select {
case conn := <-manager.register:
manager.mutex.Lock()
manager.clients[conn] = true
manager.mutex.Unlock()
case conn := <-manager.unregister:
manager.mutex.Lock()
if _, ok := manager.clients[conn]; ok {
delete(manager.clients, conn)
conn.Close()
}
manager.mutex.Unlock()
case message := <-manager.broadcast:
// Kirim data secara bersamaan ke jutaan klien terhubung
manager.mutex.RLock()
for conn := range manager.clients {
conn.WriteMessage(websocket.TextMessage, message)
}
manager.mutex.RUnlock()
}
}
}
Arsitektur Skalabilitas WebSocket Dengan Redis Pub/Sub
Saat aplikasi berkembang hingga membutuhkan puluhan server peramban (horizontal scaling), status koneksi WebSocket (stateful connection) harus terkoordinasi antar instansi server. Strategi yang teruji secara industri adalah menggunakan Redis Pub/Sub atau NATS Messaging Backplane.
Ketika peristiwa baru terjadi di salah satu server backend, pesan dipublikasikan ke kanal Redis Pub/Sub. Seluruh server WebSocket yang berlangganan kanal tersebut akan menerima event secara simultan dan meneruskannya ke koneksi peramban masing-masing dalam kurun waktu kurang dari 5 milidetik.
Kapan Harus Menggunakan Server-Sent Events (SSE)?
Meskipun WebSocket sangat kuat, tidak semua fitur realtime membutuhkan komunikasi dua arah. Untuk kasus seperti papan skor olahraga, pembaruan status pengiriman, live log streaming, atau dashboard harga saham di mana klien hanya bertindak sebagai penerima pasif, Server-Sent Events (SSE) sering kali menjadi pilihan yang lebih unggul karena berjalan di atas protokol HTTP/2 atau HTTP/3 native dengan fitur auto-reconnection built-in.
Ringkasan Utama & Best Practices
- HTTP Polling adalah utang teknis yang menguras bandwidth jaringan dan CPU basis data akibat overhead header HTTP berulang.
- Gunakan WebSocket untuk komunikasi bi-directional interaktif seperti aplikasi percakapan dan penyunting dokumen kolaboratif.
- Gunakan Server-Sent Events (SSE) untuk data streaming satu arah karena kemudahan integrasi dan kompatibilitas HTTP native.
Membutuhkan Arsitektur Realtime Berperforma Tinggi?
MAYASTRA NAWALOKA berpengalaman merancang infrastruktur WebSocket dan SSE berskala besar yang siap menangani ratusan ribu koneksi simultan secara stabil.
Konsultasi Proyek Bersama Kami