L
Laravel • Literally Web ID

Membangun Event-Driven Architecture Skala Tinggi dengan Laravel Queue & Redis

⏱️ 15 menit baca • 📅 16 Oct 2026 • 👁️ 1 views
Membangun Event-Driven Architecture Skala Tinggi dengan Laravel Queue & Redis

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap arsitektur web modern, skalabilitas dan waktu respons (latency) adalah metrik vital yang menentukan kesuksesan sebuah produk digital enterprise. Permintaan tinggi (high concurrency) pada aplikasi berbasis web sering kali menemui hambatan mendasar pada arsitektur monolitik sinkron tradisional. Ketika seorang pengguna menekan tombol 'Checkout' pada platform e-commerce skala besar, aplikasi tidak hanya harus memproses pembayaran, tetapi juga harus mengirimkan email konfirmasi transaksi, menghasilkan faktur PDF, memperbarui inventaris database, dan memicu sinkronisasi data ke sistem pihak ketiga seperti ERP atau CRM secara real-time.

Jika seluruh proses ini dieksekusi secara sinkron dalam satu siklus permintaan HTTP (request-response lifecycle), web server dan database relasional akan mengalami thread exhaustion, lonjakan penggunaan CPU, dan pemborosan koneksi database pool. Latency melonjak dari ratusan milidetik menjadi puluhan detik, yang berujung pada Gateway Timeout (HTTP 504) dan pengalaman pengguna yang buruk.

Sebelum penerapan Event-Driven Architecture (EDA) berbasis Laravel Queue dan Redis, arsitektur umum sering kali bergantung pada proses sinkron atau tabel database SQL sebagai antrean (database driver queues). Kondisi ini menyebabkan row locking pada tabel jobs, tingginya disk I/O latency pada database MySQL, dan ketidakmampuan sistem untuk pulih dengan cepat saat terjadi lonjakan traffic mendadak (traffic spike).

Setelah migrasi ke Event-Driven Architecture menggunakan Redis sebagai message broker in-memory yang dikombinasikan dengan worker daemon yang dikelola oleh Supervisor, siklus permintaan HTTP dipangkas secara drastis. Permintaan hanya perlu mendorong (dispatch) job atau event ke dalam antrean Redis dengan latensi sub-milidetik, lalu merespons klien secara instan. Proses berat dialihkan ke latar belakang (background processing) yang dieksekusi secara asinkron oleh worker berkinerja tinggi.

2. Konsep Inti & Deep Dive Arsitektur

Event-Driven Architecture (EDA) dengan Laravel dan Redis bekerja dengan memisahkan produsen kejadian (event producers / aplikasi web) dari konsumen kejadian (event consumers / queue workers). Redis bertindak sebagai in-memory data structure store yang menyediakan struktur data yang sangat efisien untuk sistem antrean, seperti Lists dan Streams.

+-----------------------+
|   Client / Browser    |
+-----------+-----------+
            |
            | HTTP Request
            v
+-----------+-----------+      Dispatch Job      +-----------------------+
|  Laravel Web Server   +----------------------->|  Redis Message Broker |
|  (Nginx / PHP-FPM)    |<-----------------------+  (In-Memory Queues)   >
+-----------+-----------+   Fast HTTP Response   +-----------+-----------+
            |                                                |
            |                                                | Pop / Dequeue
            v                                                v
+-----------------------+                        +-----------+-----------+
|   MySQL Database      |                        |  Supervisor Daemon    |
+-----------------------+                        +-----------+-----------+
                                                             |
                                                             | Manages
                                                             v
                                                 +-----------+-----------+
                                                 |  Laravel Queue Worker |
                                                 +-----------------------+

Alur Eksekusi di Balik Layar:

  1. Event Dispatching: Ketika suatu aksi terjadi di aplikasi Laravel (misal: UserRegistered), event ditangkap dan dikonversi menjadi payload JSON yang berisi nama kelas job, data serialisasi, percobaan saat ini (attempts), dan batas waktu maksimum (timeout).
  2. Broker Storage: Laravel mendorong payload tersebut ke Redis menggunakan perintah RPUSH ke dalam struktur list atau menggunakan Redis Streams. Operasi ini berjalan di dalam memori RAM, menghasilkan latensi di bawah 1 milidetik.
  3. Worker Processing: Proses daemon Supervisor memelihara sekumpulan worker PHP (php artisan queue:work) yang terus-menerus melakukan polling ke Redis menggunakan perintah BLPOP (Blocking Left Pop).
  4. Execution & Lifecycle: Worker mengambil job, mendekode payload, menginstansiasi objek job, dan mengeksekusi metode handle(). Jika berhasil, job dihapus dari antrean. Jika gagal, job ditangani sesuai konfigurasi retry dan exponential backoff.

3. Perbandingan Komparatif / Analisis Pendekatan

Berikut adalah analisis perbandingan komparatif mendalam antara tiga pendekatan queue driver yang paling sering digunakan dalam ekosistem Laravel enterprise:

Parameter / Metrik Redis Queue Driver Database Queue Driver (MySQL) Amazon SQS Driver
Kecepatan Latensi Sangat Rendah (< 2 ms) Sedang - Tinggi (Bergantung Disk I/O) Rendah - Menengah (Network API Calls)
Throughput (Ops/Sec) Sangat Tinggi (Puluhan ribu/detik) Rendah (Terbatas oleh Lock Tabel) Tinggi (Dibatasi AWS Rate Limits)
Penggunaan RAM Tinggi (In-Memory Storage) Rendah (Menggunakan Buffer SQL) Minimal (Cloud-managed)
Kompleksitas Setup Menengah (Butuh Server Redis & Supervisor) Sangat Rendah (Menggunakan DB yang sama) Menengah (Konfigurasi IAM & AWS SDK)
Biaya Infrastruktur Membutuhkan memori RAM dedicated Hanya kapasitas disk/IOPS database Pay-per-request (Biaya bertambah seiring volume)
Fitur Lanjutan Mendukung Streams, Pub/Sub, Delays Terbatas pada tabel relasional standar Mendukung Message Grouping & FIFO
Rekomendasi Skala Enterprise High-Concurrency Small to Medium Traffic Cloud-Native Enterprise Architecture

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum mengimplementasikan arsitektur ini di lingkungan produksi, pastikan server Anda memenuhi spesifikasi dan prasyarat berikut:

  • OS: Ubuntu Server 22.04 LTS / Debian 12 (Direkomendasikan)
  • PHP: Versi 8.2 atau 8.3 dengan ekstensi redis, pcntl, posix, mbstring, bcmath
  • Web Server & Runtime: Nginx + PHP-FPM
  • Databases & Broker: MySQL 8.0+ / MariaDB 10.11+ dan Redis Server 7.0+
  • Process Manager: Supervisor 4.0+

Verifikasi ekstensi PHP yang dibutuhkan melalui terminal:

php -m | grep -E 'redis|pcntl|posix|mbstring'

Pastikan ekstensi pcntl dan posix aktif karena modul ini wajib ada agar Laravel queue worker dapat menangani sinyal sistem operasi seperti SIGTERM untuk graceful shutdown.

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi Redis di Laravel (config/database.php dan .env)

Sesuaikan konfigurasi Redis di dalam file .env aplikasi Laravel Anda:

QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_CLIENT=phpredis

Pastikan konfigurasi koneksi Redis pada config/database.php menggunakan driver phpredis untuk performa optimal:

'redis' => [
    'client' => env('REDIS_CLIENT', 'phpredis'),
    'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
    ],
    'default' => [
        'url' => env('REDIS_URL'),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_DB', '0'),
    ],
    'cache' => [
        'url' => env('REDIS_URL'),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_CACHE_DB', '1'),
    ],
],

Langkah 2: Pembuatan Job Kelas Produksi

Buat file job baru menggunakan Artisan CLI:

php artisan make:job ProcessOrderFulfillment

Implementasikan logika bisnis di dalam file app/Jobs/ProcessOrderFulfillment.php:

<?php

namespace AppJobs;

use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use IlluminateSupportFacadesLog;
use Throwable;

class ProcessOrderFulfillment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $order;

    /**
     * Jumlah maksimum percobaan eksekusi job.
     */
    public int $tries = 3;

    /**
     * Waktu maksimum dalam detik job dapat berjalan sebelum timeout.
     */
    public int $timeout = 120;

    /**
     * Hapus job jika model yang diserialisasi tidak lagi ada di database.
     */
    public bool $deleteWhenMissingModels = true;

    /**
     * Buat instance job baru.
     */
    public function __construct(array $order)
    {
        $this->order = $order;
        // Tentukan antrean khusus untuk job ini
        $this->onQueue('orders');
    }

    /**
     * Eksekusi job.
     */
    public function handle(): void
    {
        Log::info('Memulai pemenuhan pesanan ID: ' . $this->order['id']);

        // Simulasi proses berat: integrasi API pembayaran, generate invoice, dll.
        usleep(500000); // Simulasi delay 0.5 detik

        if (isset($this->order['fail_test']) && $this->order['fail_test'] === true) {
            throw new Exception('Koneksi ke sistem pihak ketiga gagal.');
        }

        Log::info('Pesanan ID: ' . $this->order['id'] . ' berhasil diproses.');
    }

    /**
     * Hitung durasi waktu tunggu sebelum percobaan ulang (Exponential Backoff).
     */
    public function backoff(): array
    {
        return [10, 30, 60];
    }

    /**
     * Tangani kegagalan job setelah semua percobaan habis.
     */
    public function failed(Throwable $exception): void
    {
        Log::error('Job ProcessOrderFulfillment gagal total untuk pesanan ID: ' . $this->order['id'] . '. Pesan: ' . $exception->getMessage());
    }
}

Langkah 3: Konfigurasi Supervisor untuk Queue Workers

Supervisor adalah utilitas sistem operasi untuk sistem UNIX-like yang memantau dan mengelola proses latar belakang secara otomatis. Jika proses worker mengalami crash atau server melakukan reboot, Supervisor akan langsung menghidupkannya kembali.

Instal Supervisor pada Ubuntu/Debian:

sudo apt update && sudo apt install supervisor -y

Buat file konfigurasi baru di dalam direktori /etc/supervisor/conf.d/laravel-worker.conf:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --queue=orders,default --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killsig=SIGINT
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
stopwaitsecs=3600

[!WARNING] Pastikan parameter stopwaitsecs pada konfigurasi Supervisor diatur lebih tinggi daripada waktu timeout maksimal job Anda (timeout = 120). Jika Supervisor mengirimkan sinyal SIGKILL sebelum job selesai, job akan terhenti di tengah jalan dan memicu status failed job secara paksa.

Aktifkan dan jalankan Supervisor melalui terminal:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*

Verifikasi status worker yang berjalan:

sudo supervisorctl status

6. Bedah Kode & Penjelasan Detail Baris Kunci

Mari kita bedah beberapa parameter krusial dalam konfigurasi worker Supervisor dan kelas Job di atas:

  1. command=php /var/www/html/artisan queue:work redis --queue=orders,default Perintah ini menginstruksikan Laravel untuk mengambil job dari Redis secara berurutan. Antrean orders diprioritaskan terlebih dahulu sebelum memeriksa antrean default. Ini sangat krusial untuk memisahkan prioritas traffic (misal: notifikasi pembayaran vs laporan bulanan).

  2. numprocs=4 Menjalankan 4 instance worker secara paralel di latar belakang. Dengan alokasi ini, sistem dapat memproses hingga 4 job secara bersamaan dalam satu waktu, meningkatkan throughput secara linear sesuai kapasitas CPU core server.

  3. --sleep=3 Jika tidak ada job yang tersedia di dalam antrean Redis, worker akan berhenti/tidur selama 3 detik sebelum melakukan polling kembali. Ini mencegah lonjakan penggunaan CPU (CPU spinning) yang tidak perlu pada Redis server.

  4. public function backoff(): array { return [10, 30, 60]; } Menerapkan strategi exponential backoff. Percobaan pertama yang gagal akan menunggu 10 detik sebelum dicoba lagi. Percobaan kedua menunggu 30 detik, dan percobaan ketiga menunggu 60 detik. Pendekatan ini memberikan waktu bagi layanan eksternal (seperti payment gateway atau database pihak ketiga) untuk pulih dari gangguan beban tinggi.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Kasus: Flash Sale E-Commerce dengan 50.000 Transaksi per Menit

Pada saat acara Flash Sale, aplikasi web menerima lonjakan traffic ekstrem. Jika setiap transaksi langsung melakukan write ke database MySQL secara serentak, database akan mengalami deadlock.

Solusi Arsitektur:

  1. Penerimaan Cepat: Endpoint controller menerima request pembelian, memvalidasi stok melalui Redis atomic decrement (DECRBY), dan langsung mendispatch job ProcessOrderFulfillment ke antrean Redis.
  2. Respon Instan: Pengguna langsung mendapatkan respons HTTP 200 (Pesanan dalam antrean) dalam waktu kurang dari 40 milidetik.
  3. Asynchronous Processing: 16 instance worker Supervisor (diatur melalui numprocs=16) secara paralel mengambil job dari Redis, memproses pembayaran via API bank, dan menulis hasilnya ke MySQL secara terdistribusi dan stabil tanpa membebani koneksi pool utama.

8. Common Pitfalls, Anti-Patterns & Solusi

Berikut adalah kesalahan fatal yang sering dilakukan oleh developer dan system administrator di lingkungan produksi:

  • Anti-Pattern 1: Menyimpan Objek Model Eloquent Terlalu Besar di Payload Job

    • Masalah: Menyebarkan seluruh objek instance Eloquent dengan relasi yang sarat data ke dalam konstruktor Job akan membuat payload JSON di Redis membengkak, menghabiskan memori RAM Redis, dan memperlambat proses serialisasi.
    • Solusi: Cukup teruskan primary key (id) dari model tersebut, lalu ambil kembali model di dalam metode handle() menggunakan teknik query fresh.
  • Anti-Pattern 2: Mengabaikan Perintah php artisan queue:restart saat Deployment

    • Masalah: Ketika Anda memperbarui kode aplikasi, worker PHP yang sedang berjalan di memori Supervisor masih memuat versi kode lama (karena PHP memuat bytecode ke dalam OPcache worker saat pertama kali diinisialisasi).
    • Solusi: Tambahkan perintah php artisan queue:restart ke dalam skrip CI/CD deployment otomatis Anda setiap kali rilis baru diterapkan ke server produksi.
  • Anti-Pattern 3: Memory Leak pada Proses Long-Running Worker

    • Masalah: Berbeda dengan HTTP request standar yang siklus hidupnya singkat, proses queue worker berjalan terus-menerus di memori. Jika ada memori yang tidak dibebaskan dengan benar (misal: static cache atau query log yang menumpuk), worker akan mengalami memory exhaustion.
    • Solusi: Batasi jumlah memori maksimal atau gunakan opsi --max-jobs=1000 atau --memory=512 pada perintah worker agar proses secara otomatis di-restart oleh Supervisor setelah mencapai batas tertentu.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk menguji performa sistem antrean yang telah dibangun, Anda dapat menggunakan utilitas benchmark seperti wrk atau tool pengujian HTTP load testing, dikombinasikan dengan pemantauan Redis menggunakan redis-cli.

Jalankan perintah berikut untuk memantau performa Redis secara real-time di terminal:

redis-cli --stat

Atau memantau penggunaan memori Redis:

redis-cli info memory

Parameter Tuning Lanjutan (Redis & Linux Kernel):

  1. Maxmemory Policy: Pastikan file konfigurasi /etc/redis/redis.conf mengatur kebijakan memori yang tepat untuk menghindari penolakan tulis saat memori penuh:
    maxmemory 2gb
    maxmemory-policy noeviction
    
  2. TCP Somaxconn: Tingkatkan batas antrean koneksi TCP pada sistem operasi Linux untuk menangani ribuan koneksi masuk secara bersamaan:

sysctl -w net.core.somaxconn=1024


## 10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan arsitektur ini ke lingkungan produksi live, pastikan Anda telah mencentang seluruh poin penting dalam checklist berikut:

- [ ] Ekstensi PHP `pcntl` dan `posix` terinstal dan aktif.
- [ ] Driver queue pada file `.env` dan `config/queue.php` diset ke `redis`.
- [ ] Konfigurasi Supervisor telah diuji dengan parameter `numprocs`, `timeout`, dan `stopwaitsecs` yang selaras.
- [ ] Skrip CI/CD deployment telah menyertakan perintah `php artisan queue:restart`.
- [ ] Sistem monitoring log worker (`/var/www/html/storage/logs/worker.log`) terhubung ke sistem central logging (misal: ELK, Grafana Loki, atau Datadog).
- [ ] Mekanisme Failed Jobs menggunakan database atau tabel khusus untuk memudahkan proses *retry manual* (`php artisan queue:retry`).

Dengan mengimplementasikan Event-Driven Architecture menggunakan Laravel Queue, Redis, dan Supervisor secara tepat, aplikasi enterprise Anda tidak hanya akan mampu menangani lonjakan traffic yang masif, tetapi juga menjamin keandalan, konsistensi data, serta pengalaman pengguna yang optimal.
🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server