Worker Process #

Kecepatan dan keringan beban kerja Nginx yang legendaris tidak terjadi secara kebetulan. Berbeda dengan server web tradisional yang membuat proses atau thread baru untuk setiap koneksi pengguna, Nginx mengadopsi arsitektur asinkron berbasis peristiwa (event-driven). Inti dari arsitektur ini digerakkan oleh Worker Process.

Memahami dan menyelaraskan konfigurasi worker process dengan arsitektur perangkat keras (hardware) server kita adalah fondasi mutlak dalam mengoptimalkan performa Nginx. Penyetelan (tuning) yang salah dapat menyebabkan server kita kehabisan alokasi file descriptor, gagal memanfaatkan multi-core CPU secara maksimal, atau mengalami degradasi waktu respons saat lonjakan trafik (traffic burst). Di artikel ini, kita akan mengupas tuntas arsitektur master-worker Nginx, cara menentukan kapasitas koneksi server, teknik bypassing batas file descriptor sistem operasi menggunakan worker_rlimit_nofile, konfigurasi CPU affinity, serta menyusun berkas konfigurasi global yang siap digunakan untuk produksi skala besar.

Arsitektur Master-Worker Nginx #

Nginx beroperasi menggunakan model multi-proses yang sangat terstruktur, memisahkan tanggung jawab administratif dari pemrosesan lalu lintas data aktual. Struktur ini terbagi menjadi satu Master Process dan satu atau beberapa Worker Process.

Berikut adalah bagan alur hubungan Master-Worker di Nginx:

flowchart TD
    OS["Sistem Operasi / Network Socket (Port 80/443)"] -->|Menerima Koneksi| Master["Master Process (Root)"]
    Master -->|"Mengelola & Memantau (Spawn/Reload)"| Worker1["Worker Process 1 (www-data)"]
    Master -->|"Mengelola & Memantau (Spawn/Reload)"| Worker2["Worker Process 2 (www-data)"]
    Master -->|"Mengelola & Memantau (Spawn/Reload)"| Worker3["Worker Process 3 (www-data)"]

    Worker1 -->|"Event Loop (epoll) - Tangani Ribuan Request"| Clients1("Klien HTTP")
    Worker2 -->|"Event Loop (epoll) - Tangani Ribuan Request"| Clients2("Klien HTTP")
    Worker3 -->|"Event Loop (epoll) - Tangani Ribuan Request"| Clients3("Klien HTTP")

    classDef default fill:#f9f9f9,stroke:#d1d5db,stroke-width:1px,color:#111827;
    classDef masterStyle fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#991b1b;
    classDef workerStyle fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a;
    
    class Master masterStyle;
    class Worker1,Worker2,Worker3 workerStyle;

1. Master Process #

Master process adalah induk dari semua proses Nginx. Ia dijalankan dengan hak akses tingkat tinggi (root) karena membutuhkan wewenang untuk mengikat port jaringan bernomor rendah (seperti port HTTP 80 dan HTTPS 443) serta membaca berkas sertifikat SSL yang sensitif.

Tugas utama Master Process meliputi:

  • Membaca dan memvalidasi berkas konfigurasi Nginx (nginx.conf).
  • Membuka dan menahan soket port jaringan.
  • Membuat (spawn), memantau, dan mengatur ulang (reload) worker process.
  • Menerima sinyal kontrol sistem (seperti reload konfigurasi tanpa downtime via systemctl reload nginx atau shutdown aman).

Master process tidak pernah menangani request HTTP dari klien secara langsung. Ia mendelegasikan tugas pemrosesan tersebut sepenuhnya kepada worker process.

2. Worker Process #

Worker process dijalankan dengan hak akses pengguna terbatas (secara default menggunakan pengguna www-data atau nginx) demi alasan keamanan. Jika terjadi eksploitasi celah keamanan di sisi aplikasi web, penyerang hanya mendapatkan hak akses pengguna terbatas tersebut, bukan hak akses root.

Tugas utama Worker Process meliputi:

  • Menerima dan memproses koneksi masuk dari klien.
  • Membaca dan menulis data ke disk (jika melayani file statik atau caching).
  • Berkomunikasi dengan server backend hulu (upstream) sebagai reverse proxy.
  • Mengelola enkripsi/dekripsi SSL/TLS.

Model Event Loop Non-Blocking (epoll/kqueue) #

Untuk memahami mengapa satu thread worker Nginx dapat menangani puluhan ribu koneksi simultan, kita harus membandingkannya dengan model multi-threaded tradisional yang digunakan oleh server seperti Apache (dalam mode prefork/worker standard).

Pada server tradisional, setiap koneksi klien dialokasikan ke satu proses atau thread tersendiri. Ketika thread tersebut menunggu data dari database atau disk, thread tersebut akan berada dalam kondisi terkunci (blocked). Server harus membuat ratusan atau ribuan thread untuk melayani pengguna dalam jumlah banyak. Hal ini menyebabkan pemborosan memori RAM yang sangat besar dan membebani CPU akibat aktivitas context switching (proses CPU beralih tugas antar thread yang sangat intensif).

Nginx memotong overhead tersebut dengan menggunakan Single-Threaded Event Loop di setiap worker process. Setiap worker berjalan pada satu thread tunggal secara terus-menerus dan menggunakan panggilan sistem asinkron (non-blocking system calls) seperti epoll di kernel Linux atau kqueue di BSD/macOS.

Saat sebuah request masuk dan harus menunggu respons dari server backend, worker process Nginx tidak akan diam terpaku menunggu. Worker tersebut akan mendaftarkan koneksi tersebut ke event loop, lalu segera beralih memproses request dari klien lain yang datanya sudah siap dikirimkan. Ketika backend selesai memproses data dan mengirimkan respons balik, event loop akan memberikan notifikasi kepada worker Nginx untuk menyelesaikan request pertama tadi. Dengan cara ini, ribuan koneksi dapat ditangani secara bergantian oleh satu thread tunggal dengan overhead memori yang minimal.


Menentukan Jumlah Worker (worker_processes) #

Direktif worker_processes menentukan berapa banyak worker process yang akan dibuat oleh master process Nginx. Direktif ini ditulis di luar blok konteks http (tingkat global/main).

# Konfigurasi di tingkat global nginx.conf
worker_processes auto;

Mengapa Harus auto? #

Nilai terbaik untuk hampir seluruh skenario produksi adalah auto. Dengan nilai auto, Nginx akan mendeteksi jumlah core CPU fisik yang tersedia di server kita secara otomatis dan membuat tepat satu worker process untuk setiap core CPU.

Memiliki satu worker per core CPU sangat ideal karena:

  • Menghindari overhead pemindahan eksekusi thread antar core CPU (context switching).
  • Memastikan setiap core CPU bekerja secara paralel secara mandiri tanpa saling berebut resource.

Cara Memeriksa Jumlah Core CPU Server #

Kita dapat memeriksa jumlah core CPU yang terpasang di server Linux kita dengan menggunakan perintah CLI berikut:

# Menampilkan angka jumlah core CPU
nproc

# Atau melihat detail informasi CPU
grep -c processor /proc/cpuinfo

Jika perintah nproc mengembalikan angka 8, maka dengan konfigurasi worker_processes auto, Nginx akan menjalankan 8 worker process secara otomatis.


Mengatur Batas Koneksi per Worker (worker_connections) #

Direktif worker_connections menentukan jumlah maksimum koneksi simultan yang dapat ditangani oleh satu worker process secara bersamaan. Direktif ini ditulis di dalam blok konteks events.

events {
    # Jumlah koneksi maksimum per worker
    worker_connections 10240;
}

Menghitung Kapasitas Koneksi Maksimum Server #

Kapasitas koneksi simultan teoritis maksimum yang dapat ditangani oleh server kita dihitung dengan rumus:

$$\text{Kapasitas Maksimum} = \text{worker_processes} \times \text{worker_connections}$$

Sebagai contoh, jika server kita memiliki 4 core CPU (worker_processes 4) dan kita menyetel worker_connections ke 10240, maka kapasitas koneksi maksimum server adalah:

$$4 \times 10240 = 40.960 \text{ koneksi simultan}$$

Kapasitas Riil pada Skenario Reverse Proxy #

Perlu dicatat bahwa angka di atas adalah kapasitas koneksi teoritis. Di dunia nyata, jika Nginx kita dikonfigurasi sebagai Reverse Proxy (meneruskan trafik ke backend seperti Node.js/PHP), satu request dari klien akan memakan dua koneksi di sisi Nginx:

  1. Satu koneksi antara klien (browser) dan Nginx.
  2. Satu koneksi antara Nginx dan server backend upstream.

Oleh karena itu, kapasitas request simultan efektif pada reverse proxy dikurangi setengah dari kapasitas teoritis:

$$\text{Kapasitas Request Efektif} = \frac{\text{worker_processes} \times \text{worker_connections}}{2}$$

Dengan contoh di atas, server kita dapat melayani sekitar $20.480$ request simultan secara bersamaan.


Mengatasi Bottleneck File Descriptor: worker_rlimit_nofile #

Di dalam sistem operasi Linux, segala sesuatu direpresentasikan sebagai berkas—termasuk koneksi jaringan (network sockets). Setiap kali klien terhubung ke server kita, sistem operasi akan mengalokasikan sebuah pengenal unik yang disebut File Descriptor (FD).

Secara default, Linux menerapkan batasan jumlah file descriptor yang boleh dibuka oleh satu proses (biasanya dibatasi hanya 1024 file descriptor untuk pengguna non-root). Batasan ini disebut sebagai open files limit.

Jika trafik kita melonjak dan jumlah koneksi melebihi batas file descriptor sistem operasi, Nginx akan mulai menolak koneksi baru dan mencatat error berikut di error log:

[crit] 4821#4821: *30412 accept4() failed (24: Too many open files)

Untuk menaikkan batas ini tanpa perlu mengubah konfigurasi kernel sistem operasi secara permanen, kita menggunakan direktif worker_rlimit_nofile di tingkat global Nginx. Direktif ini memaksa sistem operasi memberikan batas file descriptor yang lebih besar khusus untuk worker process Nginx.

# Set batas file descriptor untuk seluruh worker process Nginx
worker_rlimit_nofile 65535;

events {
    # Sekarang kita aman menyetel koneksi tinggi karena rlimit telah dinaikkan
    worker_connections 10240;
}

Cara Memeriksa Batas File Descriptor Sistem Operasi #

Kita dapat memantau batasan file descriptor sistem saat ini menggunakan perintah terminal berikut:

# Cek batas file descriptor aktif (soft limit) untuk user saat ini
ulimit -n

# Cek batas maksimum sistem (hard limit)
ulimit -Hn

Jika kita ingin mengubah batas sistem secara permanen untuk seluruh sistem operasi, kita harus menyunting file /etc/security/limits.conf dan menambahkan baris berikut:

# /etc/security/limits.conf
nginx       soft    nofile   65535
nginx       hard    nofile   65535

Tuning Event Loop: use epoll dan multi_accept #

Di dalam blok konteks events, kita dapat menyetel bagaimana worker process menerima koneksi baru untuk meningkatkan efisiensi pemrosesan:

events {
    # Gunakan model event loop epoll (sangat direkomendasikan untuk Linux)
    use epoll;

    # Izinkan worker menerima semua koneksi baru di antrean sekaligus
    multi_accept on;
}

1. use epoll #

Model epoll adalah metode polling event loop yang sangat efisien yang disediakan oleh kernel Linux modern. Berbeda dengan metode lama seperti select atau poll yang memindai seluruh koneksi satu per satu untuk mencari data (O(N) complexity), epoll menggunakan sistem callback internal yang langsung menunjuk koneksi mana yang aktif (O(1) complexity). Nginx biasanya mendeteksi dan memilih model ini secara otomatis, namun mendeklarasikannya secara eksplisit menjamin konsistensi performa.

2. multi_accept on #

Secara default, ketika koneksi baru masuk, Nginx akan mengirimkan notifikasi dan worker process hanya akan mengambil satu koneksi baru dari antrean soket untuk diproses. Dengan mengaktifkan multi_accept on, worker process diinstruksikan untuk mengambil seluruh koneksi baru yang ada di antrean soket secara sekaligus dalam satu siklus event loop. Ini sangat bermanfaat untuk mempercepat waktu jabat tangan (handshake time) pada server yang mengalami lonjakan lalu lintas yang tiba-tiba (burst traffic).


Afinitas CPU (worker_cpu_affinity) #

Di dalam server multi-core modern, sistem operasi Linux bertindak sebagai penjadwal (scheduler) yang bebas memindahkan proses dari satu core CPU ke core CPU lainnya demi menyeimbangkan suhu dan beban kerja core.

Namun, pemindahan proses worker Nginx antar core CPU memiliki dampak buruk bagi performa:

  • CPU Cache Miss: Setiap core CPU memiliki memori cache cepat (L1, L2, L3) sendiri. Jika worker process dipindahkan ke core baru, data cache yang telah terkumpul di core lama menjadi tidak berguna, dan core baru harus membaca ulang data dari memori RAM yang lebih lambat.
  • Context Switch Overhead: Proses pemindahan memakan siklus CPU yang berharga.

Untuk mengunci worker process Nginx agar tetap berjalan pada core CPU tertentu secara permanen, kita menggunakan direktif worker_cpu_affinity.

Contoh Konfigurasi Afinitas CPU #

Sejak Nginx versi 1.9.10, kita dapat menyerahkan pengaturan afinitas ini secara otomatis ke Nginx menggunakan parameter auto:

# Nginx akan otomatis memetakan setiap worker ke core CPU-nya masing-masing
worker_processes auto;
worker_cpu_affinity auto;

Jika kita ingin menentukan pemetaan core secara manual (misalnya pada server dengan 4 core CPU), kita menggunakan representasi biner (bitmask):

# Server dengan 4 core CPU:
worker_processes 4;

# Pemetaan bitmask biner (Core 3, Core 2, Core 1, Core 0)
worker_cpu_affinity 0001 0010 0100 1000;
  • 0001: Worker 1 dikunci hanya pada CPU core 0.
  • 0010: Worker 2 dikunci hanya pada CPU core 1.
  • 0100: Worker 3 dikunci hanya pada CPU core 2.
  • 1000: Worker 4 dikunci hanya pada CPU core 3.

[!TIP] Menggunakan worker_cpu_affinity auto; sangat direkomendasikan karena Nginx akan mendeteksi topologi CPU secara dinamis (termasuk arsitektur multi-socket NUMA) dan memetakan proses secara optimal tanpa risiko kesalahan manusia.


Prioritisasi Scheduler Linux: worker_priority #

Di server produksi yang sibuk, Nginx sering kali harus berbagi sumber daya CPU dengan proses sistem lainnya (seperti database MySQL/PostgreSQL, logging agent, atau cron jobs). Jika CPU mengalami kelebihan beban (high CPU load), worker process Nginx harus mengantre di scheduler Linux untuk mendapatkan giliran pemrosesan, yang dapat memperlambat respons aplikasi web kita.

Kita dapat memberikan prioritas scheduling yang lebih tinggi khusus untuk worker process Nginx dengan menggunakan direktif worker_priority.

# Berikan prioritas lebih tinggi untuk worker process Nginx
worker_priority -10;

Nilai prioritas ini merujuk ke nilai nice value di penjadwal Linux:

  • Rentang nilai berkisar antara -20 (prioritas tertinggi) hingga 19 (prioritas terendah).
  • Nilai bawaan sistem adalah 0.
  • Menyetel nilai negatif (misalnya -5 atau -10) menjamin worker process Nginx didahulukan oleh scheduler Linux saat CPU sedang sibuk, meminimalkan latensi respons di saat beban server tinggi.

Contoh Konfigurasi Global Produksi yang Dioptimalkan #

Berikut adalah contoh penyusunan berkas konfigurasi global Nginx (/etc/nginx/nginx.conf) tingkat produksi yang merangkum seluruh optimasi worker process yang telah kita bahas:

# /etc/nginx/nginx.conf
# Konfigurasi Global / Main Context

user www-data;
pid /run/nginx.pid;

# 1. Optimasi Worker dan CPU Affinity
worker_processes auto;
worker_cpu_affinity auto;

# 2. Naikkan prioritas scheduling CPU
worker_priority -5;

# 3. Optimasi Batas File Descriptor
worker_rlimit_nofile 65535;

# 4. Pengaturan Log Level Produksi yang Efisien
error_log /var/log/nginx/error.log warn;

events {
    # 5. Naikkan kapasitas koneksi per worker
    worker_connections 20480;

    # 6. Gunakan model event loop terbaik Linux
    use epoll;

    # 7. Ambil koneksi antrean secara berkelompok
    multi_accept on;
}

http {
    # Konfigurasi http lainnya (gzip, cache, keepalive, vhost, dll.)
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # ...
}

Tabel Troubleshooting Masalah Koneksi & File Descriptor #

Ketika kita melakukan penyetelan batas koneksi, ada kemungkinan kita menabrak batasan sistem operasi lainnya. Berikut adalah tabel pemecahan masalah untuk kendala umum yang sering muncul:

Pesan Error di LogKemungkinan PenyebabLangkah Solutif
accept4() failed (24: Too many open files)Jumlah koneksi melebihi batas file descriptor (FD) proses worker Nginx.Naikkan nilai worker_rlimit_nofile di konfigurasi Nginx menjadi minimal 65535.
worker_connections exceed open file resource limitNilai worker_connections yang diatur lebih besar dari batasan ulimit -n sistem saat ini.Tambahkan direktif worker_rlimit_nofile dengan nilai lebih tinggi dari worker_connections dikali jumlah worker.
Connection reset by peer di error logAntrean backlog koneksi sistem operasi penuh akibat volume jabat tangan TCP yang terlalu padat.Naikkan nilai somaxconn kernel Linux di /etc/sysctl.conf: net.core.somaxconn = 65535.
Penggunaan CPU core tidak merata (satu core 100%, lainnya 0%)Konfigurasi afinitas CPU tidak aktif atau terjadi pemusatan request di satu worker.Pastikan worker_cpu_affinity auto; aktif dan gunakan load balancing internal yang merata.

Ringkasan dan Praktik Terbaik #

  • Gunakan worker_processes auto: Selalu biarkan Nginx mendeteksi dan mengalokasikan satu worker process per core CPU secara otomatis untuk paralelisme maksimal.
  • Naikkan Batas File Descriptor: Tulis direktif worker_rlimit_nofile 65535 di bagian atas berkas konfigurasi untuk mencegah kesalahan fatal “Too many open files”.
  • Gunakan Afinitas Otomatis: Aktifkan worker_cpu_affinity auto; untuk mengunci proses ke CPU core masing-masing guna mengurangi cache misses.
  • Aktifkan multi_accept: Nyalakan multi_accept on; di blok events untuk meningkatkan kecepatan penerimaan koneksi baru saat terjadi lonjakan trafik.
  • Beri Prioritas CPU: Setel worker_priority -5 di server produksi mandiri untuk menjaga stabilitas respons Nginx di bawah kondisi beban CPU tinggi.

← Sebelumnya: Rotasi Log   Berikutnya: Kompresi Gzip →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact