L
Node.js • Literally Web ID

Optimasi Nginx Reverse Proxy untuk 100.000 Koneksi WebSocket Konkuren

⏱️ 15 menit baca • 📅 12 Oct 2026 • 👁️ 1 views
Optimasi Nginx Reverse Proxy untuk 100.000 Koneksi WebSocket Konkuren

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap arsitektur web modern, kebutuhan akan komunikasi real-time dua arah (bidirectional) menjadi standar emas bagi aplikasi skala enterprise, mulai dari platform perdagangan finansial berkecepatan tinggi, sistem analitik langsung, hingga kolaborasi dokumen multi-pengguna. Protokol WebSocket (RFC 6455) hadir untuk menjawab keterbatasan HTTP tradisional yang bersifat stateless dan request-response. Dengan WebSocket, koneksi TCP tunggal dan permanen dibuka antara klien dan server, memungkinkan transmisi data berlatensi rendah tanpa overhead header HTTP berulang.

Namun, ketika sebuah infrastruktur harus melayani 100.000 koneksi WebSocket konkuren (dan terus bertambah), arsitektur server tunggal tanpa orkestrasi yang matang akan segera mengalami kegagalan fatal. Masalah utamanya bukanlah pada kemampuan aplikasi backend (seperti Go, Node.js, atau Python) itu sendiri, melainkan pada keterbatasan sistem operasi Linux dalam menangani jutaan deskriptor file (file descriptors) serta konfigurasi default Nginx yang tidak dirancang untuk menangani beban konkurensi masif di luar kotak (out-of-the-box).

Bottleneck Performa & Keamanan di Dunia Nyata

  1. Keterbatasan File Descriptor (FD): Linux secara default membatasi jumlah file yang dapat dibuka oleh satu proses (biasanya 1024 melalui ulimit -n). Setiap koneksi WebSocket merepresentasikan satu socket TCP, yang dihitung sebagai satu file descriptor oleh sistem operasi. Untuk 100k koneksi, batas ini harus dinaikkan secara drastis.
  2. Kelelahan Port Ephemeral (Ephemeral Port Exhaustion): Ketika Nginx bertindak sebagai reverse proxy yang meneruskan koneksi ke backend upstream, Nginx membuka koneksi TCP terpisah ke backend tersebut. Jika tidak dioptimalkan menggunakan Keepalive upstream, port ephemeral sistem akan habis dalam hitungan detik.
  3. Tekanan Memori Non-Paginasi (RAM Overheads): Setiap koneksi WebSocket mengonsumsi buffer memori kernel (send/receive buffer). Tanpa tuning buffer yang presisi, 100k koneksi dapat dengan mudah melahap puluhan gigabyte RAM, memicu Out-Of-Memory (OOM) Killer kernel.
  4. Handshake SSL/TLS Overhead: Proses negosiasi enkripsi (TLS handshake) untuk 100k koneksi bersamaan dapat melumpuhkan CPU. Tanpa optimasi Session Resumption dan OCSP Stapling, latensi awal koneksi akan melonjak.

Perbandingan Kondisi: Sebelum vs Sesudah Optimasi

Metrik / Parameter Sebelum Optimasi (Default) Sesudah Optimasi (Enterprise Production) Dampak Bisnis
Batas Maksimal Koneksi ~1.024 koneksi 100.000+ koneksi konkuren Skalabilitas aplikasi terjamin
Penggunaan RAM per 100k Sering OOM (Crash) Terkendali (~2 - 4 GB untuk buffer) Stabilitas server 99.999%
Latensi Handshake TCP/TLS > 350 ms < 45 ms Pengalaman pengguna real-time instan
Konsumsi CPU Idle Tinggi akibat polling sistem Minimal berkat arsitektur epoll Efisiensi biaya infrastruktur cloud

2. Konsep Inti & Deep Dive Arsitektur

Untuk memahami bagaimana Nginx mengelola 100k koneksi WebSocket, kita harus melihat mekanisme di balik layarnya (under the hood). Nginx menggunakan model event-driven, asynchronous, dan non-blocking berbasis event loop (epoll pada sistem Linux).

Alur Data & Eksekusi WebSocket lewat Nginx Reverse Proxy

+--------+       TCP Handshake &       +------------------+       Upstream Keepalive       +--------------+
| Client | --------------------------> | Nginx Reverse    | -----------------------------> | Backend App  |
| (Browser)|   Upgrade: websocket      | Proxy (epoll)    |    (Proxy Pass Persistent)     | (Go/Node/PHP)|
+--------+                             +------------------+                                +--------------+
  1. Klien mengirimkan HTTP Request dengan header khusus: Upgrade: websocket dan Connection: Upgrade.
  2. Nginx menerima request melalui event loop epoll. Karena Nginx mengenali header tersebut, Nginx tidak memperlakukan koneksi ini sebagai HTTP biasa.
  3. Nginx melakukan proxy handshake ke backend upstream. Setelah backend menyetujui, Nginx mengubah status koneksi menjadi tunnel mode transparan.
  4. Data Frame Frame Transmit: Selanjutnya, Nginx bertindak murni sebagai jembatan bi-directional proxy yang meneruskan WebSocket frames biner mentah antara klien dan backend tanpa melakukan parsing HTTP lanjutan.

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun arsitektur real-time skala besar, terdapat beberapa pilihan pendekatan server reverse proxy dan load balancing. Berikut adalah analisis mendalam:

Fitur / Parameter Nginx (epoll) HAProxy Apache (Event MPM) Caddy (Go-based)
Memory Footprint (100k Concurrence) Rendah (~3 GB) Sangat Rendah (~1.5 GB) Sedang-Tinggi (~6 GB) Sedang (~4-5 GB)
Konfigurasi SSL/TLS Sangat Matang Sangat Matang Kompleks Otomatis (Let's Encrypt)
Dukungan HTTP/2 & HTTP/3 Sangat Baik Baik Terbatas Sangat Baik
Kemudahan Integrasi WAF/Security Sangat Tinggi (Lua/ModSecurity) Baik Terbatas Terbatas
Rekomendasi Penggunaan Utama Web Proxy & API Gateway Pure Load Balancer Legacy App Host Modern Cloud Native

[!TIP] Nginx dipilih karena fleksibilitas ekosistemnya yang luas, kemampuan caching edge yang superior, serta dukungan modul pihak ketiga yang matang untuk manajemen keamanan tingkat lanjut.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menyentuh konfigurasi Nginx, sistem operasi Linux (Ubuntu 22.04 LTS / Debian 12 / RHEL 9) harus dituning terlebih dahulu untuk menaikkan batas limitasi kernel.

1. Konfigurasi Batas File Descriptor Sistem (/etc/security/limits.conf)

Tambahkan baris berikut untuk mengizinkan pengguna root dan nginx membuka file dalam jumlah tak terbatas:

# /etc/security/limits.conf
nginx     soft    nofile    500000
nginx     hard    nofile    500000
root      soft    nofile    500000
root      hard    nofile    500000

2. Tuning Kernel sysctl (/etc/sysctl.conf)

Terapkan parameter optimasi TCP stack untuk menangani trafik konkurensi tinggi:

# /etc/sysctl.conf - Enterprise WebSocket Network Tuning
fs.file-max = 2097152

# Memperbesar ukuran antrean koneksi masuk (backlog)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Mengaktifkan reuse dan recycling port TCP yang aman
net.ipv4.tcp_tw_reuse = 1

# Rentang port ephemeral yang diperluas
net.ipv4.ip_local_port_range = 1024 65535

# Tuning memori buffer TCP (Min, Default, Max dalam bytes)
# Alokasi: 4KB min, 87380B default, 16MB max untuk TCP read/write buffer
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65535 16777216

# TCP Keepalive Tuning untuk deteksi koneksi putus lebih cepat
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5

Terapkan perubahan sysctl dengan perintah:

sudo sysctl -p

5. Panduan Implementasi Langkah demi Langkah

Berikut adalah konfigurasi file utama Nginx (/etc/nginx/nginx.conf) yang telah dioptimalkan secara penuh untuk 100.000 koneksi WebSocket.

user nginx;
worker_processes auto;
worker_rlimit_nofile 500000;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 65536;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 65;
    keepalive_requests 100000;

    # SSL Optimization untuk Handshake Cepat
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # Upstream Backend untuk WebSocket dengan Keepalive
    upstream websocket_backend {
        server 127.0.0.1:8080;
        keepalive 1000;
        keepalive_timeout 60s;
    } 

    server {
        listen 80;
        server_name ws.enterprise.internal;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name ws.enterprise.internal;

        ssl_certificate /etc/letsencrypt/live/ws.enterprise.internal/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/ws.enterprise.internal/privkey.pem;

        # Buffer Tuning khusus WebSocket
        client_body_buffer_size 128k;
        client_max_body_size 10M;

        location /ws/ {
            proxy_pass http://websocket_backend;
            
            # Konfigurasi Krusial HTTP/1.1 Upgrade WebSocket
            proxy_http_version 1.1;
            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 WebSocket yang Diperpanjang (Default 60s terlalu cepat memutus koneksi idle)
            proxy_read_timeout 86400s;
            proxy_send_timeout 86400s;
            proxy_connect_timeout 60s;

            # Menonaktifkan buffering agar frame terkirim secara real-time (Low Latency)
            proxy_buffering off;
            proxy_cache off;
        }
    }
}

6. Bedah Kode & Penjelasan Detail Baris Kunci

  1. worker_processes auto; & worker_rlimit_nofile 500000;
    • auto mendeteksi jumlah core CPU secara otomatis. worker_rlimit_nofile mengubah batas maksimum file descriptor di tingkat proses Nginx, melampaui batas default sistem operasi.
  2. worker_connections 65536; & use epoll;
    • Mengatur jumlah koneksi maksimum yang dapat ditangani oleh setiap worker process. Penggunaan epoll memastikan pemantauan I/O dilakukan secara asinkron tanpa memakan siklus CPU untuk polling.
  3. keepalive 1000; pada Upstream Block
    • Memelihara kumpulan koneksi TCP persisten (hingga 1000 koneksi) yang siap digunakan kembali ke server backend, mencegah port exhaustion dan menekan latensi pembentukan koneksi baru.
  4. proxy_http_version 1.1; & Header Upgrade
    • WebSocket membutuhkan protokol HTTP/1.1 untuk mendukung mekanisme header Upgrade. Tanpa ini, Nginx akan menolak negosiasi protokol.
  5. proxy_read_timeout 86400s; & proxy_buffering off;
    • Timeout dinaikkan hingga 24 jam (86400 detik) agar koneksi persisten tidak terputus otomatis oleh Nginx saat kondisi idle. Penonaktifkan proxy_buffering memastikan paket data langsung dikirimkan ke klien tanpa menunggu buffer penuh.

7. Skenario Produksi & Studi Kasus Dunia Nyata

[!IMPORTANT] Pada lingkungan produksi dengan skala 100k+ koneksi, satu instance Nginx tunggal mungkin akan mengalami hambatan kapasitas pada antarmuka jaringan fisik (Network Interface Card / NIC Interrupts). Gunakan konfigurasi RSS (Receive Side Scaling) atau sebarkan beban melalui DNS Load Balancing / Anycast IP ke beberapa node Nginx.

Studi Kasus: Sebuah platform trading kripto mengalami lonjakan trafik hingga 120.000 klien aktif secara bersamaan saat volatilitas pasar tinggi. Dengan menerapkan arsitektur Nginx Reverse Proxy di atas yang didukung backend berbasis Go (Goroutines), latensi transmisi harga turun dari rata-rata 180ms menjadi di bawah 12ms, tanpa ada laporan koneksi terputus (dropped connection).


8. Common Pitfalls, Anti-Patterns & Solusi

  • Anti-Pattern 1: Mengaktifkan Nginx Caching pada Endpoint WebSocket.
    • Dampak: Koneksi WebSocket gagal atau merespons dengan kode error HTTP 502/504 karena Nginx mencoba menyimpan respons dalam bentuk file cache.
    • Solusi: Selalu pastikan direktif proxy_cache off; terpasang pada blok lokasi WebSocket.
  • Anti-Pattern 2: Mengabaikan TCP Keepalive pada Sisi Klien/Server.
    • Dampak: Koneksi yang terputus di tengah jalan (misal: akibat router NAT melompat atau jaringan seluler terganggu) tidak terdeteksi oleh server, menyebabkan Ghost Connections yang menghabiskan memori.
    • Solusi: Implementasikan Application-level Ping/Pong frames secara periodik setiap 30 detik di dalam protokol WebSocket.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk memvalidasi kesiapan sistem menampung 100.000 koneksi, gunakan alat beban (load testing) khusus WebSocket seperti tsung, artillery, atau script kustom berbasis Node.js/Go (websocat).

Contoh pengujian menggunakan Artillery:

config:
  target: 'https://ws.enterprise.internal'
  phases:
    - duration: 60
      arrivalRate: 500
      rampTo: 2000
scenarios:
  - engine: ws
    flow:
      - connect:
          url: '/ws/'
      - send: '{"action": "subscribe", "channel": "ticker\
🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server