Mengapa Pesan Asinkron
Lihat cara antrean memisahkan produsen dari konsumen.
Mengapa Pesan Asinkron adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar PHP Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus PHP Academy mencakup 4 pelajaran total.
Mengapa Perpesanan Asinkron
Dalam permintaan sinkron, proses PHP Anda terhenti saat berkomunikasi dengan gerbang surel, pemroses pembayaran, atau layanan hilir. Di bawah beban tinggi, hal ini membuat latensi dan ketersediaan Anda bergantung pada setiap dependensi yang dipanggil. Perpesanan asinkron memutus rantai tersebut: produsen menaruh pesan ke dalam antrean lalu segera mengembalikan hasil; konsumen memprosesnya nanti dengan kecepatannya sendiri.
Pelajaran ini membahas alasannya — pemisahan ketergantungan, penyanggaan, dan kompromi jaminan pengiriman yang harus Anda pertimbangkan sebelum menggunakan RabbitMQ atau Kafka.
Pemisahan Temporal dan Spasial
Antrean memisahkan produsen dan konsumen pada dua sumbu:
- Spasial — kedua pihak tidak memerlukan alamat pihak lainnya; mereka hanya perlu mengetahui perantara.
- Temporal — konsumen dapat tidak aktif saat produsen menerbitkan pesan; pesan tersebut akan menunggu.
Versi sinkron di bawah ini mengaitkan permintaan web dengan waktu aktif dan kecepatan peladen surat.
<?php
// Synchronous: the HTTP request blocks on SMTP
function registerUser(string $email): void {
saveUser($email);
// If SMTP is slow or down, the user waits or the request fails
sendWelcomeEmail($email); // 800ms blocking call
echo "Registered\n";
}
function saveUser(string $e): void { /* ... */ }
function sendWelcomeEmail(string $e): void { usleep(1); }
registerUser('dev@example.com');Publikasikan lalu Lanjutkan
Versi asinkron menyimpan data pengguna, menerbitkan pesan UserRegistered, lalu mengembalikan hasil. Pekerja terpisah mengirimkan surel. Kini latensi HTTP hanya bergantung pada publikasi cepat ke perantara lokal, bukan perjalanan pulang-pergi SMTP.
<?php
function registerUser(string $email): void {
saveUser($email);
// Publish a lightweight event; worker handles email later
publish('user.registered', json_encode(['email' => $email]));
echo "Registered (email queued)\n";
}
function saveUser(string $e): void { /* ... */ }
function publish(string $routingKey, string $payload): void {
echo "-> queued $routingKey: $payload\n";
}
registerUser('dev@example.com');Perataan Beban (Penyanggaan)
Lonjakan lalu lintas tidak merata, sedangkan kapasitas pemrosesan tetap. Antrean bertindak sebagai penyangga: antrean menyerap lonjakan 10.000 pesan dan memungkinkan sekumpulan pekerja memprosesnya dengan laju yang berkelanjutan. Tanpa antrean, lonjakan tersebut akan langsung membebani basis data atau API hilir.
Inilah perataan beban — Anda menukar latensi (pesan mungkin tertahan sebentar) dengan stabilitas (tidak ada komponen yang tumbang).
Jaminan Pengiriman
Setiap sistem perpesanan membuat janji pengiriman. Ketahui jaminan yang Anda gunakan:
- Paling banyak sekali — kirim lalu lupakan; pesan mungkin hilang, tetapi tidak pernah digandakan.
- Setidaknya sekali — dikirim ulang sampai dikonfirmasi; duplikat mungkin terjadi. Ini adalah bawaan yang umum.
- Tepat sekali — tidak ada kehilangan dan tidak ada duplikat; mahal dan sering kali hanya tampak benar sebagian pada lapisan aplikasi.
Karena sebagian besar sistem nyata memberikan jaminan setidaknya sekali, konsumen Anda harus mampu menangani pesan yang sama dua kali.
Konsumen Idempoten
Solusi untuk duplikat dari pengiriman setidaknya sekali adalah idempotensi: memproses pesan dua kali menghasilkan hasil yang sama seperti memprosesnya sekali. Teknik yang umum digunakan adalah kunci deduplikasi (ID pesan) yang disimpan dalam indeks unik.
<?php
function handle(array $msg, PDO $pdo): void {
$pdo->beginTransaction();
try {
// Unique constraint on message_id makes the insert the dedup gate
$stmt = $pdo->prepare(
'INSERT INTO processed_messages (id) VALUES (?)'
);
$stmt->execute([$msg['id']]);
} catch (PDOException $e) {
$pdo->rollBack();
echo "Duplicate {$msg['id']} skipped\n";
return; // already handled
}
chargeCustomer($msg['amount']);
$pdo->commit();
}
function chargeCustomer(int $a): void {}Konfirmasi dan Pengiriman Ulang
Konsumen menandakan keberhasilan dengan konfirmasi. Jika konsumen berhenti sebelum mengirim konfirmasi, perantara mengirimkan kembali pesan tersebut kepada konsumen lain. Inilah yang membuat pengiriman setidaknya sekali berjalan — tetapi berarti ack harus dilakukan setelah efek samping diterapkan, tidak pernah sebelumnya.
Konfirmasi terlalu dini dan pesan akan hilang jika terjadi kegagalan. Konfirmasi terlalu lambat lalu terjadi kegagalan, dan Anda mendapatkan duplikat — yang akan ditangani oleh lapisan idempotensi Anda.
<?php
// Pseudocode of the consumer contract
function consumeLoop($channel): void {
while ($msg = $channel->get()) {
try {
processSideEffect($msg); // commit DB write first
$channel->ack($msg); // only then ack
} catch (\Throwable $e) {
$channel->nack($msg, requeue: true); // let it redeliver
}
}
}
function processSideEffect($m): void {}Pengurutan Ada Biayanya
Antrean tidak menjamin urutan global setelah konsumen diperbanyak. Dua pekerja yang mengambil pesan dari antrean yang sama akan memprosesnya secara bersamaan, sehingga pesan B dapat selesai sebelum pesan A.
Jika urutan penting (misalnya perubahan saldo akun), Anda harus mempartisi berdasarkan kunci agar semua pesan terkait dikirim ke satu konsumen dalam urutan yang benar. Kafka mendukung hal ini secara bawaan dengan partisi; dengan RabbitMQ, Anda merutekan berdasarkan hash konsisten ke antrean per kunci.
Antrean Pesan Mati
Beberapa pesan tidak akan pernah berhasil — misalnya muatan data cacat atau referensi ke baris yang telah dihapus. Mencoba ulang pesan tersebut tanpa henti akan membuat antrean macet (menjadi pesan beracun). Polanya adalah antrean pesan mati (DLQ): setelah N upaya gagal, alihkan pesan ke tempat terpisah untuk diperiksa, alih-alih mengirimkannya kembali.
<?php
function consume(array $msg, $channel): void {
$attempts = ($msg['headers']['x-attempt'] ?? 0) + 1;
try {
process($msg);
$channel->ack($msg);
} catch (\Throwable $e) {
if ($attempts >= 5) {
$channel->deadLetter($msg); // park in DLQ
} else {
$channel->republish($msg, ['x-attempt' => $attempts]);
}
}
}
function process(array $m): void {}Kapan NOT Menggunakan Antrean
Perpesanan asinkron menambah biaya operasional yang nyata: Anda harus menjalankan perantara, menjelaskan konsistensi tertunda kepada tim produk, dan melakukan penelusuran kesalahan yang lebih sulit melintasi batas proses.
Gunakan antrean ketika pekerjaan bersifat lambat, melonjak, dapat dicoba ulang, atau dikirim lalu dilupakan. Tetap gunakan cara sinkron ketika pemanggil benar-benar memerlukan hasilnya saat ini (misalnya harga resmi yang harus dilihat pengguna) — membungkus panggilan yang membutuhkan jawaban ke dalam antrean hanya menambah latensi dan kerumitan.
Antrean vs Catatan
Ada dua bentuk umum perantara yang mendukung pola-pola ini, dan bagian selanjutnya dari kursus ini menggunakan keduanya:
- Antrean tugas (RabbitMQ) menghapus pesan setelah dikonfirmasi. Antrean ini unggul dalam membagikan pekerjaan kepada sekumpulan konsumen yang saling bersaing, dengan perutean per pesan dan masa berlaku.
- Catatan komit (Kafka) menyimpan pesan sesuai kebijakan penyimpanan; setiap konsumen melacak posisinya sendiri dan dapat memutar ulang riwayat, sementara banyak grup konsumen independen dapat membaca aliran yang sama.
Pilih antrean untuk pembagian pekerjaan, dan catatan untuk aliran peristiwa berkapasitas tinggi serta pemutaran ulang.
<?php
$useCase = 'replay events for a new analytics service';
$broker = str_contains($useCase, 'replay') || str_contains($useCase, 'stream')
? 'Kafka (commit log)'
: 'RabbitMQ (task queue)';
echo $broker . "\n";Pemeriksaan Singkat
Penalaran tentang jaminan pengiriman.
Ringkasan
Sekarang Anda memiliki model pemikiran di balik perpesanan asinkron:
- Antrean memberikan pemisahan spasial dan temporal serta bertindak sebagai penyangga untuk perataan beban.
- Sebagian besar sistem menggunakan jaminan setidaknya sekali, sehingga konsumen harus idempoten.
- Lakukan konfirmasi setelah efek samping diterapkan; biarkan kegagalan memicu pengiriman ulang.
- Pengurutan memerlukan partisi berdasarkan kunci; pesan beracun memerlukan DLQ.
- Jangan mengantrekan pekerjaan yang perlu dijawab oleh pemanggil secara sinkron.
Selanjutnya, Anda akan mempraktikkannya dengan RabbitMQ dalam PHP.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Mengapa Pesan Asinkron” gratis?
Ya — teks lengkap “Mengapa Pesan Asinkron” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus PHP Academy, upgrade ke CoddyKit PRO. Kursus PHP Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Mengapa Pesan Asinkron”?
Lihat cara antrean memisahkan produsen dari konsumen. Kamu berlatih PHP Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai PHP Academy?
Tidak diperlukan pengalaman sebelumnya. PHP Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.
Berapa lama pelajaran “Mengapa Pesan Asinkron” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran PHP Academy ini?
Ya. Setiap pelajaran PHP Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Mengapa Pesan Asinkron
- Bekerja dengan RabbitMQ di PHP
- Apache Kafka dengan PHP
- Membangun Alur Kerja Berbasis Peristiwa