Message queues are the glue of distributed systems — Kafka for throughput, RabbitMQ for flexibility, RocketMQ for transactions. This is the architecture topology of three mainstream MQs, consumer groups, partition ordering, exactly-once semantics, message backlog troubleshooting, dead-letter practice.
@startuml skinparam componentStyle rectangle skinparam defaultTextAlignment center
title "Kafka Cluster Architecture"
node "Kafka Broker 1" { queue "Topic: orders (Partition 0)" as p1_0 queue "Topic: orders (Partition 1)" as p1_1 queue "Topic: orders (Partition 2)" as p1_2 }
node "Kafka Broker 2" { queue "Topic: orders (Partition 0 replica)" as p2_0 queue "Topic: orders (Partition 1 replica)" as p2_1 queue "Topic: orders (Partition 2 replica)" as p2_2 }
node "Kafka Broker 3" { queue "Topic: payments (Partition 0)" as p3_0 queue "Topic: payments (Partition 1)" as p3_1 }
node "ZooKeeper / KRaft" as ZK { component "Cluster Metadata" as cm }
participant "Producer\n(Order Service)" as prod participant "Consumer Group A\n(Inventory Service)" as cg_a participant "Consumer Group B\n(Analytics Service)" as cg_b
@startuml title "Kafka Exactly-Once with Transactional API"
participant "Producer" as P participant "Kafka Broker" as K participant "Consumer" as C database "DB" as DB
P -> P : ① initTransactions() P -> P : ② beginTransaction()
loop process N messages P -> DB : ③ business write (local tx) P -> K : ④ send offset + record (same tx) end
P -> P : ⑤ commitTransaction()
note right of P Kafka transaction guarantees: - atomic: consume offset + business write either both succeed or both fail - idempotent: ProducerId + SequenceNumber dedup - non-duplicate: consumer only reads committed end note
C -> K : ⑥ read_committed (only committed) C -> C : ⑦ process message C -> DB : ⑧ write result C -> K : ⑨ sendToNext (forward)
rectangle "Exchange Types" { component "Direct Exchange\n(routing_key exact match)" as direct component "Topic Exchange\n(routing_key pattern match *.order.*)" as topic component "Fanout Exchange\n(broadcast all queues)" as fanout component "Headers Exchange\n(header-based routing)" as headers }
queue "Queue: order.new" as q1 queue "Queue: order.paid" as q2 queue "Queue: order.cancelled" as q3 queue "Queue: analytics" as qa queue "Queue: audit" as qau
P -> direct : "routing_key='order.new'" direct --> q1 : "routing_key='order.new'" direct --> q2 : "routing_key='order.paid'" direct --> q3 : "routing_key='order.cancelled'"
:check consumer group lag; note right kafka-consumer-groups.sh --describe --group <name> end note
if (lag high on single partition) :check consumer instance for that partition; :check consumer GC / CPU; :check downstream DB slow query; elseif (lag high on all partitions) :consumer overall slow; :check broker disk IO; :check network bandwidth; else :check producer rate; :real burst or fake; end
@startuml title "Order Event Ordering by Order ID"
participant "Order Service" as OS participant "Kafka" as K participant "Order Processor" as OP participant "Inventory Service" as INV participant "Shipping Service" as SHIP
OS -> K : ① publish OrderCreated {order_id=123} OS -> K : ② publish OrderPaid {order_id=123} OS -> K : ③ publish OrderShipped {order_id=123}
note over OS, K : key=order_id, all events route to same partition
K -> OP : ④ OrderCreated (offset 0) OP -> OP : ⑤ process create K -> OP : ⑥ OrderPaid (offset 1) OP -> OP : ⑦ process payment OP -> INV : ⑧ reserve stock K -> OP : ⑨ OrderShipped (offset 2) OP -> OP : ⑩ process ship OP -> SHIP : ⑪ create shipment
note right of OP single partition + single consumer guarantees ordered processing but cannot parallelize (same order) end note
@enduml
Key: key = order_id routes all same-order events to same partition. Single consumer per partition = ordered.
What do you need? ├─ Log streaming / big data pipeline → Kafka ├─ Complex routing / RPC style → RabbitMQ ├─ E-commerce transaction consistency → RocketMQ ├─ Simple async tasks → Redis Streams / Postgres LISTEN └─ IoT / lots of small messages → MQTT / NATS
Ordering requirement? ├─ Global order → single partition + single consumer (low throughput) ├─ Same key order → key hash partition └─ No order → multiple partitions parallel
Transaction requirement? ├─ Weak (loss acceptable) → any MQ ├─ No loss no dup → Kafka EOS / RocketMQ transaction └─ Business idempotent + at-least-once → any MQ + idempotent consumer
Minimum start: Redis Streams (simple) or RabbitMQ (single Docker). Mid-scale: Kafka single broker start, production uses 3-broker cluster. High-scale: Kafka + partitions + monitoring + DLQ + auto-scaling.
Remember: message queue is an async decoupling tool, not universal glue. Simple tasks use synchronous calls; cross-service async / burst absorption / event stream uses MQ. Wrong scenario introduces complexity.