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

Aplikasi Laravel yang cepat di laptop tapi lambat di production biasanya tidak bermasalah di kode PHP-nya. Artikel ini membahas pengaturan OPcache dan PHP-FPM, query database, queue, caching, deployment, dan pengaturan keamanan yang penting begitu trafik sungguhan mulai masuk.

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

Aplikasi Laravel yang lancar di laptop developer tapi berat di production jarang disebabkan oleh kode PHP-nya. Biasanya penyebabnya ada di tiga tempat: pengaturan runtime, jumlah query database di setiap request, dan pekerjaan berat yang dijalankan di dalam request padahal bisa diproses di background. Kalau ketiganya dibereskan, sebagian besar keluhan performa hilang tanpa perlu menulis ulang aplikasi.

Kenapa Masalah Performa Jarang Disebabkan oleh PHP

PHP versi sekarang jauh lebih cepat daripada versi lama yang dulu membuatnya dicap lambat. Untuk aplikasi bisnis pada umumnya, interpreter PHP bukan penghambatnya. Waktu sebuah request lebih banyak habis untuk menunggu: menunggu query database, menunggu API pihak ketiga yang dipanggil di tengah request, atau membaca file dan jaringan yang tidak pernah di-cache. Mengoptimasi kode sebelum tahu ke mana waktunya habis biasanya cuma menghasilkan kerja keras dengan hasil kecil.

Jadi langkah pertama adalah mengukur. Laravel Telescope di staging, Debugbar saat development, atau slow query log di database biasanya sudah menunjukkan penyebabnya dalam waktu kurang dari satu jam. Pastikan juga versi PHP yang dipakai masih mendapat update keamanan. Setiap rilis baru membawa peningkatan performa tanpa perlu mengubah kode sama sekali.

Atur Runtime PHP Sebelum Mengutak-atik Kode

Ada dua pengaturan runtime yang paling berpengaruh. Yang pertama OPcache. OPcache menyimpan hasil kompilasi script di memori, jadi PHP tidak perlu mengompilasi ulang file yang sama di setiap request. Di production, aktifkan OPcache dengan alokasi memori yang cukup untuk seluruh aplikasi. Pengecekan timestamp file juga bisa dimatikan karena file tidak berubah di antara deployment, asalkan proses deploy me-reset cache-nya setelah rilis.

Yang kedua jumlah proses PHP-FPM. Kesalahan yang sering terjadi adalah menyetel worker lebih banyak dari yang sanggup ditampung memori server. Hitung jumlah child process dari pemakaian memori satu worker saat beban nyata dan sisa memori di server, dan sisakan ruang untuk database dan cache kalau ada di mesin yang sama. Kalau angkanya terlalu tinggi, server akan swapping saat trafik naik, dan itu jauh lebih parah daripada request yang antre sebentar. Kalau terlalu rendah, kapasitas server tidak terpakai.

Untuk JIT compiler yang ada sejak PHP 8, jangan berharap terlalu banyak. JIT membantu untuk pekerjaan yang berat di komputasi. Aplikasi web kebanyakan menghabiskan waktu untuk menunggu input dan output, jadi menyalakan JIT jarang mengubah response time aplikasi Laravel biasa. Silakan dites, tapi JIT tidak menggantikan usaha mengurangi jumlah query.

Biasanya Masalahnya di Jumlah Query

Masalah performa yang paling sering ditemui di aplikasi Laravel adalah N+1 query: sebuah daftar data memicu satu query tambahan untuk setiap relasi yang diakses. Saat development dengan dua puluh baris data, masalah ini tidak terasa. Begitu datanya dua puluh ribu baris, halaman langsung lambat. Eloquent membuat pola ini gampang terjadi, tapi juga gampang diperbaiki.

GejalaPenyebab umumPerbaikan praktis
Response time naik seiring banyaknya baris yang ditampilkanRelasi dimuat secara lazy di dalam loopMuat relasi di awal dengan eager loading, dan nyalakan strict mode saat development supaya lazy loading memunculkan exception
Satu endpoint memakan memori sangat besarSemua data diambil ke memori sekaligusPakai pagination, atau proses data sedikit demi sedikit dengan chunk kalau berjalan di background
Setiap query cepat tapi halamannya tetap lambatRatusan query kecil dalam satu requestKurangi jumlah query-nya, lalu cache data yang jarang berubah
Cuma satu query yang lambat, sisanya normalKolom yang difilter atau diurutkan belum punya indexBaca execution plan, lalu tambahkan index yang cocok dengan query tersebut. Tidak perlu memberi index ke semua kolom
Aplikasi melambat hanya di jam-jam tertentuLaporan atau export berat berjalan di database production saat jam kerjaPindahkan ke queue, jadwalkan di luar jam sibuk, atau arahkan ke read replica

Biasakan juga hanya mengambil kolom yang dipakai, terutama di tabel yang punya kolom teks besar. Beban database dan memori per request jadi lebih kecil, dan itu ikut menentukan berapa banyak worker yang bisa dijalankan di satu server.

Pindahkan Pekerjaan Berat ke Luar Request

Pekerjaan yang tidak harus selesai sebelum response dikirim lebih baik dikeluarkan dari request. Kirim email, membuat dokumen, memanggil API pihak ketiga, memproses file upload, dan mengirim webhook semuanya cocok untuk queue. Laravel sudah menyediakan queue dengan backend Redis atau database, Horizon untuk memantau queue berbasis Redis, dan tabel failed job yang perlu dicek secara rutin.

Ada juga alasan lain yang sering terlewat. Kalau API pihak ketiga sedang lambat dan dipanggil langsung di dalam request, setiap worker PHP-FPM yang melayani endpoint itu ikut tertahan sampai panggilannya selesai. Akibatnya seluruh aplikasi bisa tidak bisa diakses hanya karena satu layanan luar sedang lambat. Selalu pasang timeout di setiap HTTP request keluar, dan kalau hasilnya tidak dibutuhkan saat itu juga, pindahkan ke job.

Cek cepat: cari semua pemanggilan Http:: atau Guzzle di controller, lalu pastikan masing-masing punya timeout. Tanpa timeout, satu API luar yang hang bisa menghabiskan semua worker PHP-FPM.

Pekerjaan terjadwal juga sama. Laravel cukup butuh satu entri cron yang menjalankan scheduler setiap menit, dan semua jadwal tugasnya ditulis di dalam aplikasi. Cegah tugas yang bisa berjalan tumpang tindih, dan buat setiap job yang menulis ke sistem luar aman kalau dijalankan ulang, karena queue worker memang akan melakukan retry.

Pakai Cache, Tapi Rencanakan Kapan Dihapus

Cache untuk config, route, dan view adalah bagian dari proses deployment, jadi jalankan di setiap rilis. Ada satu hal yang sering bikin tim bingung: begitu config di-cache, memanggil env() langsung di luar file config tidak lagi mengembalikan nilai. Taruh semua nilai environment di file config, lalu baca dari config.

Cache di level aplikasi butuh pertimbangan lebih. Setiap data yang di-cache perlu jelas berapa lama berlakunya dan kejadian apa yang membuatnya harus dihapus. Kalau tidak, aplikasi akan menampilkan data lama dan penyebabnya sulit dilacak. Data referensi, menu navigasi, daftar hak akses, dan query agregat yang berat cocok untuk di-cache. Data yang pengguna harapkan langsung berubah setelah mereka melakukan sesuatu sebaiknya tidak di-cache, kecuali cache-nya ikut dihapus di aksi yang sama.

Deployment Tanpa Downtime

  1. 1Install dependency production tanpa paket development dan dengan autoloader yang dioptimasi. Idealnya ini dilakukan di tahap build, tidak langsung di server production.
  2. 2Jalankan cache untuk config, route, view, dan event setelah kode baru sudah di tempatnya, supaya file cache cocok dengan rilis yang akan diaktifkan.
  3. 3Pisahkan migrasi database dari rilis kode. Perubahan yang sifatnya menambah, misalnya kolom baru yang nullable, aman dijalankan sebelum rilis. Perubahan yang menghapus kolom atau tabel dijalankan belakangan, setelah tidak ada kode yang masih memakainya.
  4. 4Aktifkan rilis baru sekaligus, misalnya dengan mengganti symlink, supaya tidak ada request yang dilayani dari folder yang baru setengah terisi.
  5. 5Restart queue worker di setiap deployment. Worker adalah proses yang berjalan lama dan akan terus menjalankan kode lama sampai di-restart. Gejalanya sering disangka masalah cache.
  6. 6Reload PHP-FPM supaya OPcache membaca kode terbaru, lalu pastikan folder storage dan cache masih bisa ditulis oleh user web server.

Pengaturan Production yang Berpengaruh ke Keamanan

  • Matikan debug mode di production. Halaman error Laravel sangat membantu saat development, tapi juga menampilkan konfigurasi dan detail environment ke siapa pun yang memicu error.
  • Buat application key satu kali untuk setiap environment dan jangan simpan di Git. Key ini dipakai untuk melindungi data terenkripsi dan data yang ditandatangani.
  • Daftarkan atribut model yang boleh diisi dari input pengguna secara eksplisit. Jangan membuka semua atribut hanya karena form-nya bertambah.
  • Taruh validasi di form request, jangan tersebar di controller, supaya aturannya gampang dicek dan sama di semua endpoint yang menerima data serupa.
  • Validasi jenis dan ukuran file upload, lalu simpan di luar folder public. Kalau isinya tidak untuk umum, sajikan lewat aplikasi dengan pengecekan akses.
  • Pasang rate limiting di login dan di endpoint yang memicu pekerjaan atau mengirim pesan. Endpoint seperti ini yang paling cepat disalahgunakan.
  • Audit dependency secara berkala, dan pakai versi PHP yang masih mendapat perbaikan keamanan.

Kapan Laravel Cocok, Kapan Kurang Cocok

Laravel pilihan yang kuat untuk aplikasi bisnis, sistem internal, panel admin, dan API, apalagi kalau kebutuhannya masih berkembang selama pengerjaan dan proyeknya harus cepat jadi. Autentikasi, queue, scheduler, notifikasi, dan testing sudah tersedia tanpa perlu merakit library sendiri. Di Indonesia, developer PHP dan Laravel juga cukup banyak, jadi proyek tidak bergantung pada satu atau dua orang saja.

Laravel kurang cocok untuk pekerjaan yang berat di komputasi, sistem yang butuh latency sangat rendah dan stabil di kisaran beberapa milidetik, atau arsitektur yang seluruhnya memakai koneksi panjang dalam skala besar. Laravel Octane membantu performa dengan menjaga aplikasi tetap di memori di antara request, tapi kodenya jadi tidak boleh bergantung pada state yang biasanya dibuang setelah setiap request, dan ini bisa jadi kendala di codebase yang sudah lama berjalan. Dalam praktiknya, pilihan framework jarang sepenting tiga hal di atas. Aplikasi Laravel yang dikonfigurasi dengan benar akan lebih cepat daripada aplikasi di bahasa apa pun yang dikonfigurasi seadanya.

Checklist Sebelum Trafik Naik

  • Halaman dengan daftar data tetap cepat walaupun jumlah datanya bertambah, karena jumlah query tidak ikut naik.
  • Kalau satu layanan pihak ketiga lambat, hanya fitur yang memakainya yang terganggu.
  • Deployment bisa diulang dengan hasil yang sama, dan queue worker otomatis di-restart.
  • Failed job dicek rutin dan tidak dibiarkan menumpuk.
  • Log error memuat konteks yang cukup untuk menjelaskan masalah tanpa harus mereproduksinya dulu.

Poin penting

  • Ukur dulu sebelum mengoptimasi. Kebanyakan masalah performa Laravel datang dari jumlah query dan pemanggilan yang memblokir, jarang dari kecepatan PHP itu sendiri.
  • Atur OPcache dan jumlah worker PHP-FPM sesuai memori server sebelum mulai mengoptimasi kode.
  • Pindahkan kirim email, export, panggilan ke pihak ketiga, dan pekerjaan lambat lainnya ke queue, dan selalu pasang timeout di HTTP request keluar.
  • Buat deployment yang bisa diulang, restart queue worker di setiap rilis, dan pastikan debug mode mati di production.
Bagikan artikel ini

Artikel terkait

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

Kode program di monitor dengan code editor bertema gelapPengembangan Backend

10 menit baca

REST API dengan JSON, XML, atau gRPC: Mana yang Tepat untuk Aplikasi Anda?

REST, JSON, XML, dan gRPC sering dibandingkan seolah-olah sejenis, padahal tidak. Apa keunggulan masing-masing, hasil pengukuran ukuran data yang sebenarnya, kapan XML masih wajib dipakai di Indonesia, dan cara sederhana memilih untuk API publik, integrasi dengan mitra, dan layanan internal.

Mari berdiskusi

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