L
Node.js • Literally Web ID

Arsitektur Real-Time Web: Membangun WebSockets Skala Tinggi dengan Soketi (Pusher Open-Source) dan Nginx Reverse Proxy

⏱️ 15 menit baca • 📅 13 Oct 2026 • 👁️ 2 views
Arsitektur Real-Time Web: Membangun WebSockets Skala Tinggi dengan Soketi (Pusher Open-Source) dan Nginx Reverse Proxy

Arsitektur Real-Time Web: Membangun WebSockets Skala Tinggi dengan Soketi (Pusher Open-Source) dan Nginx Reverse Proxy

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap pengembangan aplikasi web modern, kebutuhan akan komunikasi dua arah yang instan (real-time bidirectional communication) bukan lagi sekadar fitur tambahan, melainkan standar esensial. Dari platform kolaborasi dokumen, aplikasi chat, hingga panel dashboard analitik finansial, pengguna menuntut pembaruan data tanpa harus melakukan refresh halaman secara manual.

Secara historis, arsitektur web dibangun di atas model request-response HTTP yang bersifat stateless. Pendekatan paling awal untuk meniru perilaku real-time adalah Long Polling atau HTTP Short Polling. Pada metode polling, klien secara periodik mengirimkan permintaan HTTP ke server untuk mengecek apakah ada data baru. Pendekatan ini mendatangkan masalah fatal pada skala tinggi:

  • Overhead Jaringan yang Masif: Setiap permintaan HTTP membawa header yang ukurannya bisa mencapai ratusan byte hingga kilobyte (termasuk cookie, User-Agent, authorization token), meskipun isi payload datanya hanya beberapa byte.
  • Lonjakan Beban Server (Thundering Herd / CPU Spike): Ribuan klien yang melakukan polling setiap detik akan membanjiri antrean proses pada web server (seperti Apache atau Nginx), menghabiskan kapasitas koneksi PHP-FPM atau Node.js, dan membebani database dengan query repetitif yang sebagian besar menghasilkan data kosong (no changes).
  • Latensi Tinggi: Ada jeda waktu (latency gap) antara saat data baru tersedia di server dan saat klien berikutnya melakukan poll untuk mengambil data tersebut.

Prototipe Sebelum Penerapan (Model Long Polling Tradisional):

[Client A] --(HTTP GET: Cek Data)---> [Nginx] ---> [Backend/DB] (Respon: Kosong)
[Client A] --(HTTP GET: Cek Data)---> [Nginx] ---> [Backend/DB] (Respon: Kosong)
[Client A] --(HTTP GET: Cek Data)---> [Nginx] ---> [Backend/DB] (Respon: Ada Data Baru)

Kondisi Sesudah Penerapan (Arsitektur WebSocket dengan Soketi & Nginx):

[Client A] <===(Koneksi TCP Persisten via WebSocket)===> [Nginx Reverse Proxy] <===> [Soketi Server (Node.js)] <== (Redis Pub/Sub) ==> [Backend Aplikasi]

Dengan memanfaatkan protokol WebSocket, koneksi TCP tunggal dibuka secara persisten (persistent connection). Header HTTP hanya dikirimkan sekali pada saat proses handshake awal, setelah itu komunikasi data berlangsung melalui bingkai (frames) biner atau teks yang sangat ringan. Tantangannya, membangun server WebSocket native dari nol memerlukan manajemen state, penanganan reconnection, skalabilitas multi-node, dan protokol otorisasi yang rumit.

Di sinilah Soketi hadir sebagai penyelamat. Soketi adalah server WebSocket berperforma tinggi yang kompatibel dengan protokol Pusher (Pusher-compatible), ditulis dalam bahasa TypeScript di atas platform Node.js (µWebSockets.js), menawarkan kecepatan tinggi, konsumsi memori yang sangat rendah, serta kemampuan berjalan secara headless tanpa ketergantungan pada infrastruktur berbayar pihak ketiga.


2. Konsep Inti & Deep Dive Arsitektur

Soketi dirancang untuk menduplikasi API Pusher, yang berarti aplikasi yang sebelumnya dikonfigurasi menggunakan SDK Pusher dapat beralih ke Soketi secara instan hanya dengan mengubah konfigurasi host dan port.

Alur Kerja di Balik Layar (Under the Hood)

  1. Handshake HTTP ke WebSocket: Klien (browser) mengirimkan permintaan HTTP GET ke Nginx dengan header khusus Upgrade: websocket dan Connection: Upgrade. Nginx meneruskan permintaan ini ke proses Soketi.
  2. Upgrade Protokol: Soketi menerima permintaan tersebut, melakukan validasi, dan menyetujui transisi protokol dari HTTP ke WebSocket. Koneksi TCP kini menjadi persisten.
  3. Otorisasi Channel: Klien mencoba bergabung (subscribe) ke sebuah channel (misalnya, channel privat private-chat.1). Soketi memvalidasi token otorisasi atau mengirimkan auth request kembali ke backend aplikasi utama (misalnya Laravel/Node.js) untuk memastikan pengguna memiliki hak akses.
  4. Pub/Sub Messaging: Ketika backend ingin mengirim pesan ke channel tertentu, backend mempublikasikan pesan tersebut ke Redis Pub/Sub. Soketi yang berlangganan (subscribed) ke channel Redis yang bersangkutan akan menerima pesan tersebut secara instan dan menyebarkannya (broadcast) ke semua klien WebSocket yang terhubung ke channel tersebut.
+-------------------------------------------------------------------------+
|                         CLIENT BROWSER                                  | 
|  +--------------------+             +---------------------------------+ |
|  |   JavaScript App   |             |         Laravel Echo            | |
|  +---------+----------+             +----------------+----------------+ |
+------------|-----------------------------------------|------------------+
             | (1. HTTP Handshake & Upgrade)           | (4. Subscribe Channel)
             v                                         v
+-------------------------------------------------------------------------+
|                          NGINX REVERSE PROXY                            | 
|  - SSL Termination (Let's Encrypt)                                      | 
|  - Proxy Pass ke Soketi Port 6001                                      | 
+----------------------------+--------------------------------------------+
                             | 
                             v 
+-------------------------------------------------------------------------+
|                       SOKETI SERVER (Node.js)                           | 
|  - µWebSockets.js Core Engine                                           | 
|  - Pusher Protocol Layer                                                | 
+----------------------------+--------------------------------------------+
                             | 
            +----------------+----------------+
            | (Redis Pub/Sub Layer)           |
            v                                 v
+-----------------------+         +-----------------------+
|      REDIS SERVER     | <-----> |   BACKEND APLIKASI    | 
|  - Message Broker     |         |  - Auth Endpoints     | 
|  - Multi-node Sync    |         |  - Event Trigger      | 
+-----------------------+         +-----------------------+

3. Perbandingan Komparatif / Analisis Pendekatan

Untuk menentukan pilihan infrastruktur real-time yang optimal, mari kita lakukan analisis komparatif antara tiga pendekatan utama yang sering dipertimbangkan oleh arsitek sistem:

Parameter Komparasi Long Polling / AJAX Native WebSocket (Node.js Custom) Soketi (Pusher-Compatible on Redis)
Konsumsi CPU & RAM Sangat Tinggi (karena repetisi request HTTP) Rendah hingga Sedang (tergantung implementasi event loop) Sangat Rendah (dioptimalkan oleh pustaka dasar µWebSockets.js)
Latensi Jaringan Tinggi (tergantung interval polling, misal 2-5 detik) Sangat Rendah (< 10 ms) Sangat Rendah (< 10 ms)
Kompleksitas Kode Klien Sederhana (fetch/axios biasa) Kompleks (perlu manajemen reconnect, ping/pong manual) Sangat Mudah (menggunakan SDK standar Pusher / Laravel Echo)
Skalabilitas Multi-Server Mudah (karena stateless) Sulit (butuh Redis Adapter manual dari awal) Otomatis melalui integrasi bawaan Redis Pub/Sub
Keamanan & Autorisasi Mengikuti standar cookie/session HTTP Harus dibangun sendiri dari awal Didukung native private/presence channels out-of-the-box
Biaya Operasional Boros bandwidth server Efisien, namun biaya dev/maintenance tinggi Sangat efisien, stabil di single droplet berkapasitas kecil

[!TIP]
Jika Anda sudah menggunakan ekosistem Laravel atau aplikasi yang akrab dengan protokol Pusher, Soketi adalah jalan pintas paling efisien untuk mendapatkan performa enterprise tanpa biaya lisensi komersial Pusher.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menyelam ke proses instalasi dan konfigurasi, pastikan environment server Anda (direkomendasikan Ubuntu 22.04 LTS atau yang setara) memenuhi spesifikasi berikut:

  1. Node.js (Versi 18.x LTS atau lebih baru) dan npm:
    node -v
    npm -v
    
  2. Redis Server (Versi 6.x atau lebih baru) yang aktif dan berjalan:
    sudo systemctl status redis-server
    
  3. Domain aktif dengan SSL/TLS valid (Let's Encrypt Certbot terpasang): Pastikan sertifikat SSL untuk domain Anda (misal: socket.domainanda.com) sudah tersedia di /etc/letsencrypt/live/socket.domainanda.com/.

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Instalasi Global Soketi

Kita akan memasang Soketi secara global menggunakan npm agar dapat dikelola sebagai layanan sistem (systemd service).

sudo npm install -g @soketi/soketi

Verifikasi instalasi:

soketi --version

Langkah 2: Konfigurasi File Soketi (JSON)

Buat direktori konfigurasi khusus di /etc/soketi/ dan buat file config.json dengan konfigurasi produksi yang aman.

sudo mkdir -p /etc/soketi
sudo nano /etc/soketi/config.json

Isi file config.json dengan konfigurasi berikut:

{
  "debug": false,
  "port": 6001,
  "appManager": {
    "apps": [
      {
        "id": "app-id-production-01",
        "key": "app-key-secret-xyz123",
        "secret": "app-secret-token-abc987",
        "maxConnections": 10000,
        "enableClientMessages": true,
        "enabled": true
      }
    ]
  },
  "adapter": "redis",
  "redis": {
    "host": "127.0.0.1",
    "port": 6379,
    "password": null
  },
  "metrics": {
    "enabled": true,
    "route": "/metrics"
  }
}

Langkah 3: Membuat Systemd Service untuk Soketi

Agar Soketi berjalan di latar belakang secara terus-menerus dan otomatis restart saat server reboot, buat file service systemd.

sudo nano /etc/systemd/system/soketi.service

Masukkan konfigurasi berikut:

[Unit]
Description=Soketi WebSocket Server
After=network.target redis-server.service

[Service]
Type=simple
User=www-data
ExecStart=/usr/bin/soketi start --config=/etc/soketi/config.json
Restart=always
RestartSec=5
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=soketi

[Install]
WantedBy=multi-user.target

Uji dan aktifkan service tersebut:

sudo systemctl daemon-reload
sudo systemctl start soketi
sudo systemctl enable soketi
sudo systemctl status soketi

Langkah 4: Konfigurasi Nginx Reverse Proxy

Nginx bertindak sebagai gerbang terdepan (reverse proxy dan SSL termination). Kita wajib mengonfigurasi header Upgrade dan Connection agar koneksi WebSocket tidak diputus oleh Nginx.

Buat file blok server baru di Nginx:

sudo nano /etc/nginx/sites-available/socket.domainanda.com

Isi dengan konfigurasi produksi berikut:

server {
    listen 80;
    server_name socket.domainanda.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name socket.domainanda.com;

    ssl_certificate /etc/letsencrypt/live/socket.domainanda.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/socket.domainanda.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/soketi_access.log;
    error_log /var/log/nginx/soketi_error.log;

    location / {
        proxy_pass http://127.0.0.1:6001;
        proxy_http_version 1.1;
        
        # Header krusial untuk upgrade koneksi WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Timeout untuk mencegah koneksi terputus prematur
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Aktifkan konfigurasi dan uji sintaks Nginx:

sudo ln -s /etc/nginx/sites-available/socket.domainanda.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Langkah 5: Integrasi Sisi Klien (JavaScript & Laravel Echo)

Berikut adalah contoh implementasi koneksi menggunakan pustaka standar Laravel Echo yang dihubungkan ke Soketi.

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'app-key-secret-xyz123',
    wsHost: 'socket.domainanda.com',
    wsPort: 443,
    wssPort: 443,
    forceTLS: true,
    enabledTransports: ['ws', 'wss'],
    cluster: 'mt1', // Placeholder wajib untuk Pusher compatibility
    disableStats: true,
});

// Mendengarkan event pada public channel
window.Echo.channel('public-notifications')
    .listen('.NewNotificationEvent', (e) => {
        console.log('Pesan baru diterima:', e.message);
    });

// Mendengarkan event pada private channel (memerlukan otorisasi backend)
window.Echo.private('private-chat.1')
    .listen('.UserMessageEvent', (e) => {
        console.log('Pesan privat:', e.chat);
    });

6. Bedah Kode & Penjelasan Detail Baris Kunci

  • proxy_http_version 1.1;: Secara default, Nginx menggunakan HTTP/1.0 untuk komunikasi upstream. Protokol WebSocket memerlukan minimal HTTP/1.1 agar fitur hop-by-hop headers seperti Upgrade didukung.
  • proxy_set_header Upgrade $http_upgrade; dan proxy_set_header Connection "upgrade";: Kombinasi dua baris ini memberi tahu Nginx dan server upstream bahwa klien meminta untuk mengubah koneksi TCP HTTP biasa menjadi terowongan (tunnel) WebSocket.
  • proxy_read_timeout 86400s;: Standar timeout Nginx adalah 60 detik. Jika klien diam (idle) selama 60 detik, Nginx akan memutus koneksi. Pengaturan ke 86400 detik (24 jam) memastikan koneksi persisten aman dari pemutusan sepihak oleh Nginx.
  • "adapter": "redis": Menginstruksikan Soketi untuk menggunakan Redis sebagai penyimpanan terdistribusi. Jika Anda menjalankan klaster Soketi di beberapa server terpisah di masa depan, Redis bertindak sebagai pusat sinkronisasi pesan antar node Soketi.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Studi Kasus: Sebuah platform e-commerce dengan flash sale besar-besaran yang mendatangkan 50.000 pengguna aktif bersamaan (concurrent connections) dalam satu waktu untuk memantau perubahan stok barang secara langsung.

Strategi Implementasi Skala Tinggi:

  1. Tuning OS Kernel (sysctl.conf): Batas file descriptor default Linux (ulimit) terlalu rendah untuk menampung puluhan ribu koneksi TCP. Kita perlu menaikkan batas ini pada sistem:
    sudo nano /etc/sysctl.conf
    
    Tambahkan baris berikut:
    fs.file-max = 2097152
    net.ipv4.tcp_rmem = 4096 87380 16777216
    net.ipv4.tcp_wmem = 4096 65536 16777216
    
    Terapkan perubahan:
    sudo sysctl -p
    
  2. Horizontal Scaling Soketi: Karena Soketi mendukung Redis Pub/Sub, Anda dapat memasang Load Balancer (seperti HAProxy atau AWS ALB) di depan 3 unit server Soketi mandiri. Ketika server backend mempublikasikan event ke Redis, ketiga server Soketi akan menerima event tersebut secara serentak dan mendistribusikannya ke klien yang terhubung ke masing-masing server.

8. Common Pitfalls, Anti-Patterns & Solusi

  • Pitfall 1: Lupa Menyesuaikan nofile pada Systemd Service
    • Gejala: Server Soketi sering crash atau menolak koneksi baru dengan pesan error EMFILE: too many open files saat jumlah klien mencapai 1.024.
    • Solusi: Tambahkan baris LimitNOFILE=65536 di dalam blok [Service] pada file konfigurasi /etc/systemd/system/soketi.service.
  • Pitfall 2: Mixed Content Error pada SSL
    • Gejala: Klien gagal terhubung dan browser menampilkan error keamanan karena mencoba melakukan koneksi ws:// tidak aman dari halaman web yang dimuat melalui https://.
    • Solusi: Pastikan parameter forceTLS: true diaktifkan pada konfigurasi Laravel Echo / klien, dan Nginx memproyeksikan protokol wss:// dengan benar.
  • Pitfall 3: Salah Konfigurasi Redis Password
    • Gejala: Soketi gagal melakukan booting dan memunculkan error autentikasi Redis di syslog.
    • Solusi: Pastikan parameter password di dalam objek redis pada /etc/soketi/config.json diisi dengan string password Redis yang valid (atau biarkan null jika Redis lokal tidak menggunakan password).

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk mengukur kapasitas server Soketi yang kita bangun, kita dapat menggunakan tool pengujian beban seperti artillery atau autocannon.

Contoh pengujian menggunakan autocannon untuk mensimulasikan koneksi WebSocket:

npm install -g autocannon
autocannon -c 1000 -d 30 -m ws https://socket.domainanda.com
  • -c 1000: Mensimulasikan 1.000 klien konkuren.
  • -d 30: Durasi pengujian selama 30 detik.
  • -m ws: Mode pengujian protokol WebSocket.

Hasil Analisis Metrik Ideal:

  • Memory Footprint: Soketi dengan 10.000 koneksi aktif biasanya hanya mengonsumsi RAM sekitar 80MB hingga 150MB, jauh lebih efisien dibanding server WebSocket berbasis bahasa lain yang memakan gigabyte.
  • CPU Usage: Penggunaan CPU tetap berada di bawah 15% pada core tunggal selama kondisi idle dan lonjakan ringan.

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan infrastruktur ini ke lingkungan produksi yang sesungguhnya, pastikan seluruh item dalam checklist berikut telah diverifikasi:

  • Sertifikat SSL/TLS valid dan terpasang dengan benar di Nginx.
  • Parameter LimitNOFILE=65536 sudah diterapkan pada file systemd Soketi.
  • Firewall (UFW/iptables) hanya membuka port 80, 443, dan menutup akses langsung publik ke port internal 6001 Soketi.
  • Autentikasi token rahasia (key dan secret) pada Soketi dan klien telah disamakan dan dirahasiakan.
  • Log rotasi untuk Nginx dan Soketi telah dikonfigurasi untuk mencegah kepenuhan disk (disk full).
  • Sistem monitoring (seperti Prometheus yang membaca endpoint /metrics dari Soketi) sudah aktif.

Dengan memadukan Soketi yang ringan, Redis sebagai broker pesan yang tangguh, serta Nginx Reverse Proxy yang dikonfigurasi secara presisi, Anda kini memiliki arsitektur real-time web kelas enterprise yang siap menangani lonjakan jutaan pesan dengan latensi minimal dan efisiensi sumber daya yang maksimal.

🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server