Mengoptimalkan aplikasi untuk skala lebih besar: mengaktifkan Opcache, menyempurnakan strategi cache, indexing database, session Redis untuk multi-server, dan membuktikan hasil dengan load testing.

Aplikasi kalian sudah produksi: HTTPS, Docker, CI/CD, cache, log. Sekarang pertanyaannya: bagaimana kalau traffic naik 10x? Apakah satu server cukup, atau perlu dua? Bagaimana mengukur semuanya?
Di episode 24 ini kita membahas scaling & optimisasi — dari tuning sederhana di satu server (Opcache, PHP-FPM, indexing) hingga horizontal scaling dengan session Redis. Dan karena optimisasi tanpa pengukuran hanyalah perasaan, kita tutup dengan load testing yang membuktikan hasilnya.
Opcache menyimpan bytecode PHP terkompilasi di memori — tidak perlu menerjemahkan file PHP setiap request. Ini satu-satunya optimisasi dengan pengembalian terbesar untuk usaha terkecil:
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.validate_timestamps = 0validate_timestamps = 0 berarti Opcache tidak mengecek perubahan file setiap request — cepat, tapi jangan aktifkan di development (file yang diedit tidak ter-reload sampai cache dibersihkan atau PHP-FPM di-restart). Verifikasi:
php -i | grep opcache.enable
php spark env | grep OPcache # atau lewat halaman infoWarning
opcache.validate_timestamps = 0 hanya untuk produksi. Di development, matikan atau set 1 agar setiap edit langsung terlihat. Salah setting di development membuat kalian bertanya "kenapa kode saya tidak berubah?" padahal Opcache menyimpan versi lama.
Di episode 14 kita punya cache-aside + invalidation. Di produksi, rapikan jadi strategi menyeluruh:
| Layer | Isi | Driver |
|---|---|---|
| Page cache | Halaman publik (cachePage()) | File/Redis |
| Data cache | Hasil query berat (list, laporan) | Redis |
| Session | Login state semua user | Redis |
cache.default.handler = redis
cache.redis.host = 127.0.0.1
cache.redis.port = 6379
session.driver = RedisHandler
session.savePath = 'tcp://127.0.0.1:6379'Mengapa Redis untuk keduanya? Karena state dibagikan antar server — ketika nanti ada 2+ instance aplikasi, session dan cache yang disimpan di file lokal akan tidak konsisten (login di server A tidak dikenali server B). Redis adalah single source of truth untuk semua instance.
Index mempercepat query yang memfilter atau mengurutkan kolom. Tambahkan lewat migration (bukan manual):
public function up()
{
$this->forge->addKey('slug'); // WHERE slug = ...
$this->forge->addKey('category_id'); // WHERE category_id = ...
$this->forge->addKey(['status', 'created_at']); // composite: filter + sort
$this->forge->processIndexes('posts');
}Aturan praktis indexing:
WHERE/JOIN/ORDER BY.EXPLAIN sebelum menambah index.php spark db:query "EXPLAIN SELECT * FROM posts WHERE status='published' ORDER BY created_at DESC"EXPLAIN menunjukkan apakah query memakai index (possible_keys/key) atau melakukan full table scan (type: ALL). Ini bukti, bukan tebakan.
PHP-FPM mengelola proses PHP. Konfigurasi pool di /etc/php/8.4/fpm/pool.d/www.conf:
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.max_requests = 500pm.max_children = maksimum proses bersamaan; patokan umum: RAM server / RAM per request.pm.max_requests = 500 — proses di-restart setelah 500 request, mencegah kebocoran memori.Jangan menaikkan max_children membabi buta — setiap proses makan memori. Hitung: server 2 GB dengan rata-rata request 50 MB → sekitar 30-40 max_children adalah batas aman.
Setelah tuning, buktikan dengan load test. Dua tool umum:
ab -n 1000 -c 50 http://localhost/hey -n 1000 -c 50 http://localhost/-n 1000 = total 1000 request, -c 50 = 50 concurrent. Metrik yang diperhatikan:
| Metrik | Arti | Target wajar |
|---|---|---|
Requests per second | Throughput | Naik setelah optimisasi |
Time per request (mean) | Latensi rata-rata | Stabil di peningkatan traffic |
Failed requests | Harus 0 | 0 |
Percentage served within | Latensi p95/p99 | Sekitar 2-5x latensi rata-rata |
Tip
Bandingkan sebelum dan sesudah setiap optimisasi: matikan cache → ukur, aktifkan cache → ukur, matikan Opcache → ukur. Angka yang berubah menunjukkan apa yang benar-benar berpengaruh — dan mencegah optimisasi yang hanya terasa di kepala.
Saat satu server tidak cukup (atau ingin high availability), tambah instance aplikasi. Kunci horizontal scaling:
Prasyarat untuk multi-server:
writable/ di storage bersama (atau pindahkan upload ke S3/object storage).Tanpa poin 1-3, menambah server justru menimbulkan bug sesi acak — user login di server A tapi server B tidak mengenalinya.
validate_timestamps = 0 hanya di produksi.EXPLAIN.pm.max_children dihitung dari RAM, pm.max_requests mencegah leak.ab/hey, bandingkan sebelum-sesudah, fokus pada p95 & failed requests.Inti yang harus dibawa pulang:
EXPLAIN hanyalah tebakan.Di episode 25 selanjutnya kita akan membahas ekosistem & tren modern 2026 — fitur CodeIgniter 4.7.x, Shield dan Queue, perbandingan dengan Laravel dan Symfony, serta arah PHP 8.4/8.5 dan modernisasi dari CI3. Pilihan framework yang tepat untuk kebutuhan yang tepat!