身為前端或全端開發者,你一定有過這種經驗:畫面上一個按鈕,背後卻要同步呼叫訂單、庫存、通知、簡訊四個服務。只要其中一個慢了半秒,使用者的滑鼠就轉圈圈;只要其中一個掛了,整條請求就跟著報錯。模組越多,這種「牽一髮動全身」的耦合越要命。這時候,訊息佇列(Message Queue, MQ)就是那條幫你拆開系統、疏導流量的「傳送帶」。
一、什麼是訊息佇列
訊息佇列本質上是一個先進先出(FIFO)的中介緩衝區。生產者(Producer)把訊息丟進佇列就即刻返回,不用等下游處理;消費者(Consumer)按照自己的步調從佇列取出訊息慢慢消化。三個角色構成基本模型:
- Producer(生產者):產生事件的一方,例如「使用者下單」。
- Broker(中介):佇列伺服器本身,負責暫存與分發,例如 RabbitMQ、Kafka。
- Consumer(消費者):處理事件的一方,例如「發送通知」的服務。
生活比喻:它就像公司的「收發室」或物流中心。你(生產者)把包裹丟進去就走人,收發室(Broker)先幫你保管,再由快遞(消費者)依序送出。即使快遞今天請假,包裹也不會消失,明天照送。
二、為什麼你需要它
- 解耦:生產者不必知道誰來消費,新增一個消費者不影響原有流程。
- 異步:耗時任務(寄信、轉檔、推播)丟進佇列,主流程瞬間回應。
- 削峰:雙十一瞬間湧入十萬筆訂單,佇列像水庫一樣把洪峰蓄住,後端按能力慢慢消化,避免被打垮。
- 可靠:訊息持久化,消費失敗可重試,不丟單。
三、兩位常見選手:Kafka 與 RabbitMQ
雖然都叫 MQ,但性格迥異:
- RabbitMQ:基於 AMQP 協議,路由靈活(直連、主題、扇形交換器),延遲低,適合「任務分發、RPC、即時通知」。
- Kafka:高吞吐的分散式日誌流,採「分區(Partition)+ 消費群組」模型,適合「海量事件流、日誌採集、即時大數據」。在威脅情報平台這類需要串接告警、資產、日誌的場景,Kafka 常是骨幹。
四、實戰:用 Node.js 跑通一條 RabbitMQ 佇列
我們用最簡單的 amqplib 示範「下單後非同步發通知」。
步驟 1:安裝與啟動。本地用 Docker 拉起 Broker:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
npm install amqplib
步驟 2:連線並宣告佇列(生產者)。
const amqp = require('amqplib');
async function send(order) {
const conn = await amqp.connect('amqp://localhost');
const ch = await conn.createChannel();
await ch.assertQueue('order_notify', { durable: true });
ch.sendToQueue('order_notify', Buffer.from(JSON.stringify(order)), { persistent: true });
console.log('已送入佇列:', order.id);
await ch.close(); await conn.close();
}
send({ id: 'ORD-1006', user: 'edwin', amount: 880 });
步驟 3:消費者訂閱並處理。
async function consume() {
const conn = await amqp.connect('amqp://localhost');
const ch = await conn.createChannel();
await ch.assertQueue('order_notify', { durable: true });
ch.consume('order_notify', (msg) => {
const order = JSON.parse(msg.content.toString());
console.log('發送通知給', order.user);
ch.ack(msg); // 處理成功才確認
});
}
步驟 4:前端拿到結果。消費者處理完可把結果寫入資料庫,前端再用輪詢或 WebSocket 推送刷新;若走 Kafka,還能直接讓前端訂閱即時事件流。
五、前端視角的注意點
你雖然不直接維運 Broker,但設計介面時要理解:使用者點完按鈕拿到的是「已受理」,不是「已完成」。記得給「處理中」狀態與最終回執,而不是假裝同步成功。
重點:三個生產環境必須面對的坑——冪等性(消費者重試不能重複扣款,用唯一訂單號去重)、死信佇列(DLQ)(處理失敗的訊息隔離出來人工補單,別讓毒訊息卡死整條佇列)、順序性(Kafka 同一 Partition 內才保序,涉及帳戶餘額這類強順序場景要小心分區鍵)。
互動話題:你在專案裡用過訊息佇列嗎?是 RabbitMQ、Kafka,還是雲端的 SQS / Pulsar?最棘手的一次「訊息積壓或重複消費」是怎麼解決的?歡迎留言分享你的踩坑經驗。