Message queues decouple producers from consumers, enabling async processing and buffering traffic spikes. Kafka extends this to a durable, replayable event log serving multiple consumer groups simultaneously.
Produce messages and watch them distributed across 6 partitions. Simulate a consumer rebalance when a consumer leaves.
| Feature | Kafka | RabbitMQ | SQS |
|---|---|---|---|
| Message retention | Days/weeks (log) | Until consumed (deleted) | Up to 14 days |
| Multiple consumers | Yes — each group independent | No — message consumed once | No — one consumer per msg |
| Replay | Yes — seek to any offset | No | No |
| Throughput | ~1M msgs/sec per broker | ~50K msgs/sec | ~3000 msgs/sec per queue |
| Best for | Event streaming, audit logs, real-time analytics | Task queues, RPC, routing | Simple async decoupling on AWS |
from confluent_kafka import Producer, Consumer, KafkaError
# Producer: send order events
producer = Producer({
'bootstrap.servers': 'kafka1:9092,kafka2:9092,kafka3:9092',
'acks': 'all', # wait for all replicas
'retries': 3,
'enable.idempotence': True, # exactly-once producer
})
def send_order(order: dict):
producer.produce(
topic='orders',
key=order['user_id'], # same key → same partition
value=json.dumps(order).encode(),
callback=lambda err, msg: print(f'Delivered to {msg.partition()}@{msg.offset()}')
)
producer.flush()
# Consumer: billing service
consumer = Consumer({
'bootstrap.servers': 'kafka1:9092',
'group.id': 'billing-service',
'auto.offset.reset': 'earliest',
'enable.auto.commit': False, # manual commit for control
})
consumer.subscribe(['orders'])
while True:
msg = consumer.poll(1.0) # pull model
if msg is None: continue
if msg.error(): raise Exception(msg.error())
order = json.loads(msg.value())
process_billing(order) # idempotent: safe to retry
consumer.commit(msg) # commit AFTER processing