Memeras performa Swoole secara ilmiah: tuning worker_num, max_request, enable_coroutine, dan dispatch_mode, setelan kernel Linux, metodologi benchmark yang benar, serta perbandingan Swoole vs Nginx+PHP-FPM vs Go.

Setelah di episode 19 kita mengamati server — pada episode kali ini kita memperbaiki apa yang teramati. Tuning performa adalah pekerjaan paling membingungkan bagi pemula Swoole: ada puluhan setelan, dan salah set justru memperlambat. Kuncinya bukan menghafal angka ajaib, melainkan memahami apa yang diukur setiap setelan.
Mengapa episode ini penting? Karena performa adalah alasan utama orang memilih Swoole. Tuning yang benar membuat server melayani ribuan RPS dengan memory kecil — tuning yang asal membuatnya lebih lambat dari PHP-FPM. Dan untuk membuktikannya, kalian harus tahu cara benchmark yang jujur.
Jumlah worker proses. Aturan dasar: sebanyak core CPU:
$server->set([
'worker_num' => swoole_cpu_num(),
]);| Nilai | Efek |
|---|---|
| Kurang dari core | Core menganggur — performa kurang |
| Sebanyak core | Utilisasi CPU optimal untuk CPU-bound |
| Jauh lebih banyak | Context switching berlebihan — lebih lambat |
Ingat: worker adalah interpreter PHP utuh. Setiap worker menambah memory; 8 worker × 100 MB = 800 MB baseline.
Jumlah request per worker sebelum direcycle (proses dimatikan, diganti yang baru). Fungsinya mencegah kebocoran memory menumpuk:
$server->set([
'max_request' => 100000,
]);| Nilai | Trade-off |
|---|---|
| Terlalu kecil | Restart sering → overhead bootstrap |
| Terlalu besar | Memory leak perlahan naik (tergantung kode) |
0 (tidak pernah) | Leak bisa menggerus memory tanpa batas |
Mulai dari 100000, lalu pantau memory di episode 19 — turunkan bila naik terus.
Mengaktifkan/menonaktifkan coroutine di worker:
$server->set(['enable_coroutine' => true]);Selalu true untuk aplikasi modern. Matikan hanya bila kalian sengaja memakai model callback klasik (jarang di 2026).
Cara Master membagi request ke worker:
| Mode | Cara kerja | Kapan |
|---|---|---|
1 | Round-robin bergilir | Default, merata |
2 | Fixed: satu worker dipilih acak, tetap selama koneksi | Session sticky per koneksi |
3 | Preemptive: ke worker yang paling idle | Beban tidak merata |
4 | Hash IP client | Session sticky per IP |
5 | Hash UID (dari uid di request) | Sticky per user |
$server->set(['dispatch_mode' => 3]);Jumlah thread reactor yang membaca socket (hanya berlaku di mode SWOOLE_BASE). Di mode SWOOLE_PROCESS (default), reactor diatur otomatis. Jarang perlu disentuh.
Swoole memanfaatkan kernel Linux secara agresif — beberapa setelan sysctl membantu di beban tinggi:
sudo sysctl -w net.core.somaxconn=4096 # antrian koneksi pending
sudo sysctl -w net.ipv4.tcp_tw_reuse=1 # reuse TIME_WAIT socket
sudo sysctl -w net.ipv4.ip_local_port_range="1024 65535"
ulimit -n 1000000 # batas file descriptor| Setelan | Melindungi/memperbaiki |
|---|---|
net.core.somaxconn | Antrian backlog — menolak koneksi terlalu cepat |
net.ipv4.tcp_tw_reuse | Kehabisan port di koneksi cepat (TIME_WAIT) |
ulimit -n | File descriptor — setiap koneksi butuh 1 FD |
Periksa batas FD dengan ulimit -n; server dengan puluhan ribu koneksi butuh FD puluhan ribu juga.
Benchmark bohong lebih buruk daripada tidak ada. Empat aturan:
Tool yang umum:
wrk -t8 -c400 -d30s --latency http://127.0.0.1:9501/hey -z 30s -c 400 http://127.0.0.1:9501/Baca tiga angka utama: Requests/sec, Latency p99, dan Transfer — RPS tinggi dengan latensi p99 membengkak bukanlah kemenangan.
Benchmark NpgsqlRest (Juli 2026) memberi gambaran realistis: Swoole menang 14 dari 38 kombinasi — bukan "PHP mengalahkan segalanya", melainkan "di workload yang tepat, PHP coroutine bersaing dengan Go".
| Aspek | Nginx+PHP-FPM | Swoole | Go |
|---|---|---|---|
| Model | Per-request process | Coroutine di worker tetap | Goroutine per koneksi |
| Memory/request | Tinggi (bootstrap tiap request) | Kecil (24 MB avg di benchmark) | Rendah-sedang |
| Cold start | Sedang | Sangat cepat (tidak restart tiap request) | Cepat |
| State in-memory | Tidak ada | Ada (Table/Atomic) | Ada |
| Kapan menang | Simpel, sudah ada | Realtime, concurrency, memory kecil | CPU-bound, ekosistem besar |
Warning
Jangan memilih teknologi hanya dari angka RPS murni (hello world). Benchmark yang bermakna memakai workload nyata: query database, JSON parsing, koneksi pool. NpgsqlRest menguji hal ini — dan di sanalah Swoole unggul: bukan di "echo hello", tapi di gabungan performa + memory.
# 1. Baseline
wrk -t8 -c400 -d30s --latency http://127.0.0.1:9501/
# 2. Naikkan worker_num sesuai core
php server.php # setelah ubah config
# 3. Ukur lagi, bandingkan RPS + p99 + memory
# 4. Ulangi sampai menemukan titik terbaikCatat setiap perubahan di tabel kecil — tanpa catatan, tuning kalian hanyalah menebak.
| Masalah | Penyebab | Solusi |
|---|---|---|
| RPS turun saat worker_num naik | Terlalu banyak worker = context switching | Kembalikan ke swoole_cpu_num() |
| Memory naik terus antar benchmark | max_request terlalu besar / ada leak | Turunkan max_request, cari leak (episode 19) |
| Hasil benchmark tidak stabil | Beban background / GC | Isolasi pengujian, ulangi 3×, ambil median |
| Timeout port saat beban tinggi | ip_local_port_range sempit | Perlebar range port, aktifkan tcp_tw_reuse |
Pada episode 20 ini, kalian telah belajar tuning dan benchmark yang benar.
Inti yang harus dibawa pulang:
worker_num = jumlah core; max_request mencegah leak; enable_coroutine selalu on.dispatch_mode menentukan distribusi request — pilih sesuai kebutuhan sticky session.somaxconn, tcp_tw_reuse, ulimit -n.Di episode 21 selanjutnya, kita mengeksplorasi protokol di bawah HTTP: TCP/UDP & Game/IoT Servers — protokol custom dengan length-header, UDP, dan MQTT untuk game dan device gateway. Sampai jumpa di episode 21!