Semua artikel

Optimasi PHP dan Laravel di Production - Performa, Queue, dan Deployment

Aplikasi Laravel yang terasa cepat saat development tetapi lambat di production biasanya tidak bermasalah pada kode PHP-nya. Panduan ini membahas konfigurasi runtime, perilaku query database, pemrosesan background, strategi caching, deployment, dan pengaturan keamanan yang penting ketika trafik nyata mulai masuk.

Pengembangan Backend|Dipublikasikan |10 menit baca
Kode aplikasi PHP yang sedang dibuka di editor saat proses development

Aplikasi Laravel yang berjalan mulus di laptop developer tetapi berat di production jarang bermasalah pada kode PHP-nya. Pada sebagian besar kasus, perbedaannya berasal dari tiga hal, yaitu bagaimana runtime dikonfigurasi, berapa banyak query database yang dihasilkan setiap request, dan seberapa banyak pekerjaan yang dijalankan di dalam request padahal seharusnya diproses di background. Memahami ketiga hal tersebut menyelesaikan sebagian besar keluhan performa tanpa perlu menulis ulang apa pun.

Mengapa Masalah Performa PHP Jarang Disebabkan PHP

Rilis PHP modern jauh lebih cepat dibandingkan versi yang dulu membentuk reputasi bahasa ini, dan untuk aplikasi bisnis pada umumnya interpreter bukanlah faktor pembatas. Waktu request biasanya didominasi oleh proses menunggu, khususnya menunggu query database, menunggu panggilan API eksternal yang dilakukan di dalam request, serta operasi file atau jaringan yang tidak pernah di-cache. Mengoptimasi kode sebelum mengukur ke mana waktu tersebut sebenarnya habis cenderung menghabiskan banyak tenaga dengan hasil yang sangat kecil.

Langkah pertama yang praktis karena itu adalah pengukuran, bukan refactoring. Laravel Telescope pada environment staging, Debugbar saat development, atau slow query log pada database umumnya sudah menunjukkan penyebabnya dalam waktu satu jam. Menjalankan versi PHP yang masih mendapat pembaruan keamanan juga termasuk dalam pembahasan ini, karena setiap rilis terbaru membawa peningkatan performa yang tidak memerlukan perubahan kode sama sekali.

Atur Runtime PHP Sebelum Mengoptimasi Kode

Dua pengaturan runtime menyumbang sebagian besar perbedaan antara deployment yang lambat dan yang cepat. OPcache menyimpan bytecode hasil kompilasi di memory sehingga script tidak dikompilasi ulang pada setiap request, dan di production sebaiknya diaktifkan dengan alokasi memory yang cukup untuk seluruh aplikasi. Validasi timestamp dapat dinonaktifkan di production karena file tidak berubah di antara deployment, dengan syarat proses deployment membersihkan atau mereset cache tersebut setelahnya.

Pengaturan kedua adalah jumlah proses PHP-FPM, dan kesalahan yang umum terjadi adalah menetapkan worker lebih banyak daripada yang mampu ditampung memory. Jumlah child process sebaiknya dihitung dari pemakaian memory satu worker pada kondisi beban nyata dan memory yang tersedia di server, dengan menyisakan ruang untuk database dan cache jika keduanya berada di mesin yang sama. Nilai yang terlalu tinggi menyebabkan swapping saat trafik naik, dan kondisi itu jauh lebih buruk dibandingkan request yang antre sebentar, sementara nilai yang terlalu rendah membuat kapasitas server tidak terpakai.

JIT compiler yang hadir sejak PHP 8 perlu disikapi dengan ekspektasi yang realistis. Manfaatnya terasa pada beban kerja yang berat secara komputasi, sedangkan aplikasi web pada umumnya menghabiskan waktu untuk menunggu proses input dan output, bukan untuk perhitungan, sehingga mengaktifkannya jarang mengubah response time aplikasi Laravel standar. Hal ini layak diuji alih-alih diasumsikan, dan tetap bukan pengganti dari upaya menekan jumlah query.

Jumlah Query Biasanya Menjadi Penyebab Utama

Masalah performa yang paling sering ditemui pada aplikasi Laravel adalah pola query N plus one, yaitu ketika sebuah daftar data memicu satu query tambahan untuk setiap relasi yang diakses. Pola ini tidak terlihat saat development dengan dua puluh baris data dan langsung terasa ketika datanya mencapai dua puluh ribu. Eloquent membuat pola tersebut mudah terbentuk, tetapi juga mudah diperbaiki.

GejalaPenyebab umumPerbaikan praktis
Response time bertambah seiring banyaknya baris yang ditampilkanRelasi dimuat secara lazy di dalam perulanganMuat relasi di awal dengan eager loading, dan aktifkan strict mode saat development agar lazy loading memunculkan exception
Satu endpoint memakai memory dalam jumlah besarSeluruh data diambil ke memory sekaligusGunakan pagination, atau proses data secara bertahap dengan chunk jika berjalan sebagai background task
Setiap query cepat tetapi halamannya tetap lambatRatusan query kecil dalam satu requestKurangi jumlah query alih-alih mengoptimasi satu per satu, dan cache data yang jarang berubah
Hanya satu query yang lambat sementara sisanya normalKolom yang difilter atau diurutkan belum memiliki indexBaca execution plan dan tambahkan index yang sesuai dengan kondisi query sebenarnya, bukan pada semua kolom
Aplikasi hanya melambat pada waktu tertentuProses laporan atau export berjalan di database production pada jam kerjaPindahkan proses baca yang berat ke queue, jadwalkan di luar jam sibuk, atau arahkan ke read replica

Mengambil hanya kolom yang benar-benar dipakai merupakan kebiasaan kecil yang tetap berguna, terutama pada tabel yang memuat field teks berukuran besar. Kebiasaan ini mengurangi beban database sekaligus memory yang dipakai setiap request, dan pada akhirnya memengaruhi berapa banyak worker yang sanggup dilayani server.

Pindahkan Pekerjaan Berat ke Luar Request

Apa pun yang tidak harus selesai sebelum response dikirim sebaiknya tidak berada di dalam request. Pengiriman email, pembuatan dokumen, pemanggilan API pihak ketiga, pemrosesan file unggahan, dan pengiriman webhook semuanya merupakan pekerjaan queue. Laravel menyediakan queue dengan Redis atau database sebagai backend, Horizon untuk memantau queue berbasis Redis, serta tabel failed job yang seharusnya ditinjau, bukan dibiarkan.

Ada pula alasan ketersediaan yang sering terlewat. Ketika API eksternal menjadi lambat dan pemanggilannya berada di dalam request, setiap worker PHP-FPM yang menangani endpoint tersebut akan tertahan sampai panggilan itu selesai, sehingga sebuah aplikasi dapat menjadi tidak dapat diakses hanya karena dependency-nya lambat, bukan karena mati. Panggilan HTTP keluar harus selalu menetapkan timeout, dan jika hasilnya tidak dibutuhkan saat itu juga, tempatnya adalah di dalam job.

Sebuah aplikasi menjadi tidak andal bukan ketika kodenya lambat, melainkan ketika ia menunggu tanpa batas pada sesuatu yang berada di luar kendalinya.

Pekerjaan terjadwal mengikuti prinsip yang sama. Laravel mengharapkan satu entri cron yang menjalankan scheduler setiap menit, sementara tugas-tugasnya didefinisikan di dalam aplikasi. Tugas yang berpotensi saling tumpang tindih perlu dicegah secara eksplisit, dan setiap job yang menulis ke sistem eksternal sebaiknya ditulis agar aman ketika diulang, karena queue worker memang melakukan retry secara bawaan.

Terapkan Caching dengan Rencana Invalidasi

Caching untuk config, route, dan view merupakan langkah deployment, bukan optimasi tambahan, sehingga sebaiknya dijalankan pada setiap rilis. Keduanya juga memunculkan perilaku yang rutin mengejutkan tim, karena begitu config di-cache, pembacaan environment variable secara langsung di luar file konfigurasi tidak lagi mengembalikan nilai. Nilai environment seharusnya ditempatkan di file konfigurasi, dan aplikasi membacanya dari sana.

Caching pada level aplikasi membutuhkan pertimbangan lebih. Setiap nilai yang di-cache memerlukan keputusan tentang berapa lama ia dianggap valid dan apa yang membatalkannya, karena tanpa itu aplikasi akan menyajikan data usang dengan cara yang sulit ditelusuri. Data referensi, struktur navigasi, daftar hak akses, dan query agregat yang mahal merupakan kandidat yang baik. Data yang diharapkan pengguna berubah seketika setelah mereka melakukan sesuatu umumnya bukan kandidat yang tepat, kecuali cache-nya ikut dibersihkan sebagai bagian dari aksi tersebut.

Deployment Tanpa Downtime dan Tanpa Kejutan

  1. 1Pasang dependency untuk production tanpa paket development dan dengan autoloader yang dioptimasi, idealnya pada tahap build, bukan langsung di server production.
  2. 2Jalankan caching config, route, view, dan event setelah kode baru berada di tempatnya, sehingga file cache sesuai dengan rilis yang akan diaktifkan.
  3. 3Perlakukan migrasi database sebagai pertimbangan terpisah dari kode. Perubahan yang bersifat menambah, misalnya kolom baru yang nullable, aman dijalankan sebelum rilis, sedangkan perubahan yang menghapus sebaiknya menyusul setelah tidak ada kode berjalan yang bergantung pada struktur lama.
  4. 4Aktifkan rilis baru secara atomik, menggunakan pergantian symlink atau mekanisme setara, agar tidak ada request yang dilayani dari direktori yang baru terisi sebagian.
  5. 5Restart queue worker pada setiap deployment. Worker adalah proses yang berjalan lama dan akan terus menjalankan kode versi sebelumnya sampai di-restart, sehingga menimbulkan perilaku membingungkan yang terlihat seperti masalah cache.
  6. 6Reload PHP-FPM agar OPcache membaca kode terbaru, lalu pastikan direktori storage dan cache tetap dapat ditulis oleh user web server setelah rilis berjalan.

Pengaturan Production yang Berdampak pada Keamanan

  • Debug mode wajib dinonaktifkan di production. Halaman error Laravel sangat membantu saat development dan sekaligus menampilkan nilai konfigurasi serta detail environment kepada siapa pun yang memicu exception.
  • Application key sebaiknya dibuat satu kali untuk setiap environment dan tidak disimpan di version control, karena kunci tersebut melindungi data terenkripsi dan data bertanda tangan.
  • Perlindungan mass assignment ada karena alasan yang jelas. Atribut model yang berasal dari input pengguna sebaiknya didaftarkan secara eksplisit, bukan dibuka seluruhnya ketika form bertambah.
  • Validasi sebaiknya ditempatkan di form request, bukan tersebar di controller, agar aturannya mudah ditinjau dan konsisten antar endpoint yang menerima data serupa.
  • File unggahan perlu divalidasi jenis dan ukurannya serta disimpan di luar direktori publik, dengan akses dilayani melalui aplikasi jika isinya memang tidak untuk publik.
  • Rate limiting perlu diterapkan pada proses autentikasi dan pada endpoint yang memicu pekerjaan atau mengirim pesan, karena endpoint seperti itulah yang paling awal disalahgunakan.
  • Dependency perlu diaudit secara berkala, dan versi PHP yang digunakan sebaiknya tetap berada dalam rentang yang masih menerima perbaikan keamanan.

Kapan Laravel Tepat dan Kapan Kurang Sesuai

Laravel merupakan pilihan yang kuat untuk aplikasi bisnis, sistem internal, antarmuka administrasi, dan API, terutama ketika kebutuhan masih berkembang selama pengerjaan dan kecepatan delivery menjadi pertimbangan. Ekosistemnya sudah mencakup autentikasi, queue, penjadwalan, notifikasi, dan testing tanpa perlu merakitnya dari pustaka terpisah, dan di Indonesia ketersediaan developer PHP serta Laravel cukup besar sehingga sebuah proyek tidak bergantung pada satu atau dua orang saja.

Laravel kurang sesuai untuk beban kerja yang berat secara komputasi, untuk sistem yang menuntut latensi rendah dan konsisten dalam hitungan milidetik satu digit, serta untuk arsitektur yang sepenuhnya dibangun di atas koneksi berdurasi panjang pada skala besar. Laravel Octane menjawab sebagian persoalan performa dengan mempertahankan aplikasi di memory antar-request, meskipun pendekatan itu menuntut kode yang tidak bergantung pada state yang selalu dibuang setelah setiap request, dan hal tersebut menjadi batasan nyata pada codebase yang sudah berjalan. Pemilihan framework umumnya tidak sepenting tiga hal yang dibahas di atas, karena aplikasi Laravel yang dikonfigurasi dengan benar akan mengungguli aplikasi yang dikonfigurasi seadanya dalam bahasa apa pun.

Seperti Apa Deployment Laravel yang Sehat

Pada deployment yang dikelola dengan baik, response time tetap stabil seiring bertambahnya data karena jumlah query tidak ikut bertambah mengikuti banyaknya baris yang ditampilkan. Layanan pihak ketiga yang lambat atau bermasalah hanya menurunkan satu fitur, bukan menjatuhkan seluruh aplikasi. Proses deployment dapat diulang dengan hasil yang sama, queue worker restart secara otomatis, dan failed job ditinjau alih-alih menumpuk tanpa disadari. Error tracker relatif sepi, dan ketika benar-benar terjadi masalah, log-nya memuat konteks yang cukup untuk menjelaskannya tanpa perlu mereproduksi kejadian terlebih dahulu.

Tidak ada bagian dari kondisi tersebut yang menuntut keahlian luar biasa. Yang dibutuhkan adalah runtime yang dikonfigurasi secara sadar, database yang diakses dengan cermat, dan pekerjaan lambat yang dipindahkan keluar dari jalur request. Ketiganya bersama-sama menjelaskan sebagian besar perbedaan antara aplikasi yang tumbuh dengan tenang dan aplikasi yang menuntut perhatian setiap minggu.

Poin penting

  • Ukur sebelum mengoptimasi. Sebagian besar masalah performa Laravel berasal dari jumlah query dan pemanggilan yang memblokir, bukan dari kecepatan eksekusi PHP.
  • Konfigurasikan OPcache dan tentukan jumlah worker PHP-FPM sesuai memory yang tersedia sebelum masuk ke optimasi pada level kode.
  • Pindahkan pengiriman email, export, pemanggilan pihak ketiga, dan pekerjaan lambat lainnya ke queue, serta selalu tetapkan timeout pada request HTTP keluar.
  • Buat proses deployment yang dapat diulang, restart queue worker pada setiap rilis, dan pastikan debug mode selalu nonaktif di production.

Artikel terkait

Artikel lain tentang software development, AI, cloud, dan infrastruktur.

Dashboard monitoring yang menampilkan status ketersediaan layanan
Monitoring Infrastruktur|

Monitoring Uptime dengan Uptime Kuma: Panduan Praktis

Pelajari cara menggunakan Uptime Kuma untuk monitoring uptime secara praktis. Panduan ini membahas penempatan instance, jenis monitor, retry, notifikasi, status page, dan pemeliharaan monitoring.

Rak server di data center yang dipantau secara berkelanjutan
Monitoring Infrastruktur|

Monitoring Server dengan Zabbix: Panduan Implementasi Praktis

Memasang Zabbix hanyalah langkah awal. Sistem monitoring akan berguna ketika alert yang dihasilkan relevan, infrastruktur terpantau dengan baik, dan tim mengetahui tindakan yang perlu dilakukan. Panduan ini membahas arsitektur Zabbix, monitoring server, desain trigger, alerting, dan strategi implementasi yang dapat mengikuti perkembangan infrastruktur.

Sedang mencari partner untuk pengembangan software?

Ceritakan proyek yang sedang Anda bangun, kebutuhan yang ingin diselesaikan, dan tantangan yang dihadapi. Kami dapat membantu membahas pendekatan teknis, scope, timeline, dan estimasi biaya.

Mulai diskusi