[{"data":1,"prerenderedAt":691},["ShallowReactive",2],{"article-\u002Farticles\u002Fkafka-vs-rabbitmq":3},{"id":4,"title":5,"body":6,"date":677,"description":678,"excerpt":679,"extension":680,"meta":681,"navigation":682,"path":683,"seo":684,"stem":685,"tags":686,"__hash__":690},"articles\u002Farticles\u002Fkafka-vs-rabbitmq.md","Kafka 與 RabbitMQ 差在哪？從「佇列」和「日誌」兩種模型看怎麼選",{"type":7,"value":8,"toc":657},"minimark",[9,38,41,46,53,59,89,94,118,121,124,278,282,287,319,326,330,352,359,363,386,388,404,407,426,429,432,444,447,450,466,469,474,506,511,543,549,553,556,601,608,611,651,654],[10,11,12,13,18,19,23,24,18,28,32,33,37],"p",{},"前面分別寫過 ",[14,15,17],"a",{"href":16},"\u002Farticles\u002Frabbitmq-exchange-queue-binding","RabbitMQ 的 Exchange、Queue、Binding","、",[14,20,22],{"href":21},"\u002Farticles\u002Frabbitmq-ack-prefetch-dead-letter","RabbitMQ 的 Ack 與死信佇列","，以及 ",[14,25,27],{"href":26},"\u002Farticles\u002Fkafka-topic-partition-consumer-group","Kafka 完整入門",[14,29,31],{"href":30},"\u002Farticles\u002Fkafka-broadcast-ordering-k8s-scaling","Kafka 實務注意事項","。兩個我都在專案中用過，最常被問的問題就是：「",[34,35,36],"strong",{},"那到底要用哪一個？","」",[10,39,40],{},"答案要從它們最根本的差異開始講。",[42,43,45],"h2",{"id":44},"核心差異佇列-vs-日誌","核心差異：佇列 vs 日誌",[10,47,48],{},[49,50],"img",{"alt":51,"src":52},"RabbitMQ 與 Kafka 核心模型比較：RabbitMQ 是佇列模型，Producer 發布到 Exchange，由 Broker 依 Binding 路由並推送給 Consumer，Consumer Ack 之後訊息就從 Queue 刪除，Broker 負責記住每則訊息的狀態，是聰明的 Broker、單純的 Consumer；Kafka 是日誌模型，Producer 附加到 Partition 尾端，Consumer 自己拉取並記錄 Offset，訊息讀完不刪除、依保留期限清除，不同的 Consumer Group 可以各自讀到不同的位置甚至倒回重讀，是單純的 Broker、聰明的 Consumer","\u002Fimages\u002Farticles\u002Fkafka-vs-rabbitmq-model.svg",[10,54,55,58],{},[34,56,57],{},"RabbitMQ 是佇列（Queue）","：",[60,61,62,66,77,83],"ul",{},[63,64,65],"li",{},"Broker 負責路由：Producer 交給 Exchange，Exchange 依 Binding 決定複製到哪些 Queue",[63,67,68,69,72,73,76],{},"Broker ",[34,70,71],{},"主動推送","訊息給 Consumer，並追蹤",[34,74,75],{},"每一則訊息","的狀態（未投遞、處理中、已 Ack）",[63,78,79,80],{},"Consumer Ack 之後，",[34,81,82],{},"訊息就從 Queue 刪除",[63,84,85,86],{},"一句話：",[34,87,88],{},"聰明的 Broker、單純的 Consumer",[10,90,91,58],{},[34,92,93],{},"Kafka 是日誌（Log）",[60,95,96,99,106,113],{},[63,97,98],{},"Producer 只是把訊息附加到 Partition 的尾端，Broker 不做路由",[63,100,101,102,105],{},"Consumer ",[34,103,104],{},"自己拉取","，自己記錄讀到哪個 Offset，Broker 不追蹤個別訊息",[63,107,108,109,112],{},"訊息讀完",[34,110,111],{},"不刪除","，依保留期限或容量清除，任何人都可以從任何位置重讀",[63,114,85,115],{},[34,116,117],{},"單純的 Broker、聰明的 Consumer",[10,119,120],{},"幾乎所有其他的差異，都是從這裡推出來的。",[42,122,123],{"id":123},"逐項比較",[125,126,127,142],"table",{},[128,129,130],"thead",{},[131,132,133,136,139],"tr",{},[134,135],"th",{},[134,137,138],{},"RabbitMQ",[134,140,141],{},"Kafka",[143,144,145,157,168,179,190,201,212,223,234,245,256,267],"tbody",{},[131,146,147,151,154],{},[148,149,150],"td",{},"模型",[148,152,153],{},"佇列，處理完就刪除",[148,155,156],{},"日誌，依保留期限清除",[131,158,159,162,165],{},[148,160,161],{},"投遞方式",[148,163,164],{},"Broker 推送（Push）",[148,166,167],{},"Consumer 拉取（Pull）",[131,169,170,173,176],{},[148,171,172],{},"處理進度",[148,174,175],{},"Broker 追蹤每則訊息的 Ack",[148,177,178],{},"Consumer Group 記錄 Offset",[131,180,181,184,187],{},[148,182,183],{},"路由",[148,185,186],{},"Exchange + Binding，可依 Routing Key、萬用字元過濾",[148,188,189],{},"只有 Topic，過濾要在 Consumer 端做",[131,191,192,195,198],{},[148,193,194],{},"重讀歷史訊息",[148,196,197],{},"不行，Ack 後就消失",[148,199,200],{},"可以，把 Offset 倒回去",[131,202,203,206,209],{},[148,204,205],{},"分工的平行度",[148,207,208],{},"同一個 Queue 加 Consumer 就好，沒有上限",[148,210,211],{},"受 Partition 數量限制",[131,213,214,217,220],{},[148,215,216],{},"順序",[148,218,219],{},"單一 Queue 單一 Consumer 時有序",[148,221,222],{},"Partition 內有序，用 Key 控制",[131,224,225,228,231],{},[148,226,227],{},"單則失敗處理",[148,229,230],{},"Nack、Requeue、死信佇列，內建",[148,232,233],{},"沒有單則 Ack，重試與死信要自己做",[131,235,236,239,242],{},[148,237,238],{},"延遲訊息",[148,240,241],{},"TTL + 死信，或 Delayed Message 外掛",[148,243,244],{},"沒有內建",[131,246,247,250,253],{},[148,248,249],{},"優先權",[148,251,252],{},"支援 Priority Queue",[148,254,255],{},"不支援",[131,257,258,261,264],{},[148,259,260],{},"吞吐量",[148,262,263],{},"每秒數萬筆等級",[148,265,266],{},"每秒數十萬到百萬筆等級",[131,268,269,272,275],{},[148,270,271],{},"訊息堆積",[148,273,274],{},"堆積太多會影響效能，Queue 應該保持接近空",[148,276,277],{},"堆積是常態，資料本來就存在磁碟上",[42,279,281],{"id":280},"同一個需求兩邊怎麼做","同一個需求，兩邊怎麼做",[283,284,286],"h3",{"id":285},"分工多個-worker-一起處理","分工：多個 Worker 一起處理",[60,288,289,302],{},[63,290,291,293,294,297,298,301],{},[34,292,138],{},"：多個 Consumer 連到",[34,295,296],{},"同一個 Queue","（Competing Consumers）。工作量大就加 Consumer，",[34,299,300],{},"沒有上限","，搭配 Prefetch 讓慢的 Worker 少拿一點",[63,303,304,306,307,314,315,318],{},[34,305,141],{},"：多個 Consumer 使用",[34,308,309,310],{},"同一個 ",[311,312,313],"code",{},"group.id","。平行度上限是 ",[34,316,317],{},"Partition 數量","，Consumer 比 Partition 多的部分只會閒置",[10,320,321,322,325],{},"所以像「產生報表」「轉檔」這種",[34,323,324],{},"每件工作要跑好幾秒到好幾分鐘","、數量又會暴增的任務，RabbitMQ 隨時加 Worker 的彈性比較好用。",[283,327,329],{"id":328},"廣播每個服務都要收到","廣播：每個服務都要收到",[60,331,332,341],{},[63,333,334,336,337,340],{},[34,335,138],{},"：每個服務",[34,338,339],{},"各自宣告一個 Queue","，綁到同一個 Fanout 或 Topic Exchange",[63,342,343,345,346,351],{},[34,344,141],{},"：每個服務使用",[34,347,348,349],{},"不同的 ",[311,350,313],{}," 訂閱同一個 Topic",[10,353,354,355,358],{},"兩者都能做，但 Kafka 的優勢是：",[34,356,357],{},"新加入的服務可以從頭讀起","，拿到上線之前的歷史事件；RabbitMQ 的新 Queue 只會收到綁定之後的訊息。",[283,360,362],{"id":361},"只收某些訊息路由與過濾","只收某些訊息：路由與過濾",[60,364,365,377],{},[63,366,367,369,370,373,374],{},[34,368,138],{},"：Topic Exchange 的 Binding Key 用萬用字元過濾，例如 ",[311,371,372],{},"house.*.franchise"," 只收加盟物件，",[34,375,376],{},"不需要的訊息根本不會送到 Consumer",[63,378,379,381,382,385],{},[34,380,141],{},"：Consumer 會讀到整個 Topic，",[34,383,384],{},"不需要的訊息要自己丟掉","。如果某類訊息只有少數 Consumer 關心，通常會拆成獨立的 Topic",[283,387,216],{"id":216},[60,389,390,395],{},[63,391,392,394],{},[34,393,138],{},"：單一 Queue 的訊息是先進先出，但只要有多個 Consumer 或發生 Requeue，順序就不保證。要嚴格有序，只能一個 Queue 一個 Consumer，等於放棄平行處理",[63,396,397,399,400,403],{},[34,398,141],{},"：用 Key 讓同一個實體的訊息進同一個 Partition，",[34,401,402],{},"同一個實體有序、不同實體平行","，這是 Kafka 的強項",[283,405,406],{"id":406},"處理失敗的訊息",[60,408,409,418],{},[63,410,411,413,414,417],{},[34,412,138],{},"：每則訊息獨立 Ack，失敗的那一則可以 Nack 送進延遲重試或死信佇列，",[34,415,416],{},"其他訊息照常處理","。這些機制都是內建的",[63,419,420,422,423],{},[34,421,141],{},"：Consumer 提交的是「讀到哪個位置」，沒有「單獨標記某一則失敗」的概念。失敗的訊息要嘛原地重試、卡住整個 Partition，要嘛自己發到重試 Topic、死信 Topic，",[34,424,425],{},"全部要自己設計",[283,427,428],{"id":428},"延遲處理",[10,430,431],{},"「訂單 30 分鐘沒付款就自動取消」這種需求：",[60,433,434,439],{},[63,435,436,438],{},[34,437,138],{},"：TTL 加死信，或安裝 Delayed Message 外掛，訊息到時間才投遞",[63,440,441,443],{},[34,442,141],{},"：沒有內建，通常要另外搭配排程或資料庫",[283,445,446],{"id":446},"事後重新處理",[10,448,449],{},"發現上週的資料處理錯了，修好程式要重跑一次：",[60,451,452,457],{},[63,453,454,456],{},[34,455,138],{},"：訊息早就刪掉了，只能從資料庫或其他來源重新產生",[63,458,459,461,462,465],{},[34,460,141],{},"：只要還在保留期限內，",[34,463,464],{},"把 Consumer Group 的 Offset 倒回上週","，重新消費一次就好",[42,467,468],{"id":468},"怎麼選",[10,470,471,58],{},[34,472,473],{},"選 RabbitMQ 的情境",[60,475,476,482,488,494,500],{},[63,477,478,481],{},[34,479,480],{},"背景工作佇列","：寄信、產生 PDF、轉檔，每件工作獨立、處理時間長短不一，需要隨時增加 Worker",[63,483,484,487],{},[34,485,486],{},"需要複雜路由","：依事件類型、來源、地區把訊息分給不同的系統，讓 Broker 幫忙過濾",[63,489,490,493],{},[34,491,492],{},"每則訊息要個別處理成敗","：失敗的要重試、重試不了的進死信佇列，不能卡住其他訊息",[63,495,496,499],{},[34,497,498],{},"需要延遲、優先權、RPC","（Request／Reply）這類訊息層級的功能",[63,501,502,503],{},"訊息量是每秒數千到數萬筆，",[34,504,505],{},"處理完就不需要再看",[10,507,508,58],{},[34,509,510],{},"選 Kafka 的情境",[60,512,513,519,525,531,537],{},[63,514,515,518],{},[34,516,517],{},"大量的事件串流","：日誌、監控指標、點擊紀錄、IoT 感測資料，每秒數十萬筆",[63,520,521,524],{},[34,522,523],{},"同一份資料要給很多系統用","，而且新系統要能補讀歷史資料",[63,526,527,530],{},[34,528,529],{},"需要重播","：修正錯誤後重新處理、用事件重建讀取模型",[63,532,533,536],{},[34,534,535],{},"同一個實體的事件需要有序","，又需要大量平行處理，例如帳務、交易事件",[63,538,539,542],{},[34,540,541],{},"CDC（Change Data Capture）","：把資料庫的異動串流到其他系統",[10,544,545,546],{},"如果一句話：",[34,547,548],{},"要「把工作交出去」用 RabbitMQ，要「把發生的事情記下來，讓大家各自去讀」用 Kafka。",[42,550,552],{"id":551},"使用情境一個系統同時用兩個","使用情境：一個系統同時用兩個",[10,554,555],{},"兩者並不互斥。以一個電商的下單流程為例：",[60,557,558,583],{},[63,559,560,561,564,565,568,569],{},"訂單建立、付款、出貨等",[34,562,563],{},"業務事件","寫進 Kafka 的 ",[311,566,567],{},"order-events","，以訂單 ID 為 Key：\n",[60,570,571,577,580],{},[63,572,573,574,576],{},"搜尋與報表服務各自用不同的 ",[311,575,313],{}," 消費，建立自己的讀取模型",[63,578,579],{},"資料分析平台從 Kafka 取得完整的歷史事件",[63,581,582],{},"讀取模型的邏輯改了，就把 Offset 倒回去重建",[63,584,585,586,589,590],{},"「寄送訂單確認信」「產生電子發票 PDF」這類",[34,587,588],{},"背景工作","丟進 RabbitMQ：\n",[60,591,592,595,598],{},[63,593,594],{},"Worker 數量隨工作量隨時增減",[63,596,597],{},"寄信失敗就延遲重試，信箱格式錯誤就進死信佇列，不影響其他人的信",[63,599,600],{},"「30 分鐘未付款自動取消」用延遲訊息處理",[10,602,603,604,607],{},"判斷的方式是看",[34,605,606],{},"這則訊息的本質","：它是「一件已經發生、很多人可能有興趣的事實」，還是「一件需要有人去完成的工作」。",[42,609,610],{"id":610},"注意事項",[60,612,613,623,629,639,645],{},[63,614,615,618,619,622],{},[34,616,617],{},"不要把 Kafka 當工作佇列用","：處理時間長的工作容易超過 ",[311,620,621],{},"max.poll.interval.ms"," 觸發 Rebalance；一則失敗會卡住整個 Partition；Worker 數量又受 Partition 限制。這些都是 RabbitMQ 擅長的",[63,624,625,628],{},[34,626,627],{},"不要把 RabbitMQ 當事件儲存用","：Queue 裡堆積大量訊息會吃記憶體與磁碟、拖慢效能，它的設計是讓 Queue 盡量保持接近空的狀態。需要長期保存、重播的，交給 Kafka 或資料庫",[63,630,631,634,635,638],{},[34,632,633],{},"兩邊的「至少一次」都一樣","：不管是 RabbitMQ 的手動 Ack 還是 Kafka 的先處理再提交 Offset，",[34,636,637],{},"訊息都可能被處理不只一次","，Consumer 一定要冪等",[63,640,641,644],{},[34,642,643],{},"維運成本不同","：RabbitMQ 單機就能跑起來，管理介面直覺；Kafka 需要規劃 Partition、複本、保留期限、磁碟容量，叢集維運的門檻比較高。訊息量不大、團隊又沒有 Kafka 經驗時，不要只因為「Kafka 比較快」就選它",[63,646,647,650],{},[34,648,649],{},"兩者都在互相靠近","：RabbitMQ 3.9 加入了 Streams，提供類似 Kafka 的可重讀日誌；Kafka 4.0 也以 Early Access 推出了 Share Group（KIP-932），讓多個 Consumer 可以不受 Partition 限制地分工、逐筆確認。不過這些都還是各自的「延伸功能」，選型時還是以核心模型為主",[42,652,653],{"id":653},"一句話總結",[10,655,656],{},"RabbitMQ 是聰明的 Broker 加處理完就刪除的佇列，擅長路由、逐筆確認、延遲與重試，適合把工作交出去；Kafka 是單純的 Broker 加可以重讀的日誌，擅長大吞吐量、多系統各自消費、依 Key 有序與重播，適合把發生的事記下來讓大家各自讀；分清楚訊息是「工作」還是「事實」，就知道該放在哪裡。",{"title":658,"searchDepth":659,"depth":659,"links":660},"",2,[661,662,663,673,674,675,676],{"id":44,"depth":659,"text":45},{"id":123,"depth":659,"text":123},{"id":280,"depth":659,"text":281,"children":664},[665,667,668,669,670,671,672],{"id":285,"depth":666,"text":286},3,{"id":328,"depth":666,"text":329},{"id":361,"depth":666,"text":362},{"id":216,"depth":666,"text":216},{"id":406,"depth":666,"text":406},{"id":428,"depth":666,"text":428},{"id":446,"depth":666,"text":446},{"id":468,"depth":659,"text":468},{"id":551,"depth":659,"text":552},{"id":610,"depth":659,"text":610},{"id":653,"depth":659,"text":653},"2025-09-16","前面分別寫過 RabbitMQ 的 Exchange、Queue、Binding、RabbitMQ 的 Ack 與死信佇列，以及 Kafka 完整入門、Kafka 實務注意事項。兩個我都在專案中用過，最常被問的問題就是：「那到底要用哪一個？」",null,"md",{},true,"\u002Farticles\u002Fkafka-vs-rabbitmq",{"title":5,"description":678},"articles\u002Fkafka-vs-rabbitmq",[141,138,687,688,689],"Message Queue","事件驅動","系統設計","soWPtmtjPIvk2bATkXgPKXPBZ9wVF9UHHIfESfsHJyw",1792959150213]