Kafka vs Traditional Queues (RabbitMQ & AWS SQS)
Distributed append-only commit log & event streaming platform. Consumers independently pull and commit sequential partition offsets. Retains immutable events regardless of consumption. Engineered for extreme throughput (millions of msg/s via zero-copy sendfile and page cache), event replayability, and multi-consumer fanout.
Executive Summary: Log vs Queue Paradigm
In distributed systems design, choosing between Apache Kafka and traditional message queues (AWS SQS, RabbitMQ) is one of the most critical architectural decisions.
The fundamental distinction lies in their core abstraction:
- Apache Kafka is a distributed append-only commit log. Messages are written sequentially to immutable disk segments, retained based on time or size, and read via independent, cursor-based consumer group offsets. Consuming a message does not delete it.
- Traditional Message Queues (RabbitMQ, SQS) are ephemeral task queues. Messages exist solely to coordinate asynchronous worker execution. Once a worker acknowledges (
ACK) a message, the broker removes it from memory/storage.
Kafka (Distributed Append-Only Commit Log):
[ Record 0 ][ Record 1 ][ Record 2 ][ Record 3 ][ Record 4 ]...
▲ ▲
│ (Offset 1) │ (Offset 3)
[ Consumer Group A ] [ Consumer Group B ]
(Replay anytime; messages remain durable)
Traditional Queue (Ephemeral Work Queue - SQS / RabbitMQ):
[ Msg 1 ][ Msg 2 ][ Msg 3 ] ──Push/Poll──> [ Worker Pool ]
│
ACK
▼
[ Msg Deleted ]
Architectural Comparison Matrix
| Architectural Dimension | Apache Kafka | AWS SQS (Standard / FIFO) | RabbitMQ (AMQP 0-9-1) |
|---|---|---|---|
| Core Abstraction | Distributed append-only partition log | Managed cloud message queue | AMQP Exchange-Binding-Queue broker |
| Delivery Model | Consumer Pull (polling via poll()) | Worker Pull (short/long polling up to 20s) | Broker Push (TCP socket channel to worker) |
| Data Retention | Durable: Retained by days (retention.ms) or log compaction | Transient: Max 14 days; deleted immediately on DeleteMessage ACK | Transient: Memory-first; deleted immediately on worker ACK |
| Message Replay | Native: Any consumer group can rewind offset to point-in-time | Unsupported: Consumed messages are permanently expunged | Unsupported: Consumed messages are permanently expunged |
| Per-Message Retries | Non-native: Requires non-blocking retry topic pipelines | Native: Automatic Visibility Timeout + Redrive Policy | Native: Dead-Letter Exchange (DLX) + per-message TTL |
| Head-of-Line Blocking | High Risk: Failing message blocks partition without retry topics | Zero: Other workers process subsequent messages concurrently | Zero: Competing workers pull subsequent messages |
| Ordering Scope | Total order per partition (Murmur2 key hashing) | Best-effort (Standard) or strict per MessageGroupId (FIFO) | Total order per single queue (broken by competing consumer NACKs) |
| Throughput Ceiling | Extreme: msg/sec per node (Zero-copy sendfile) | Near-infinite (Standard); 3,000–30,000 msg/sec (FIFO with batching) | Moderate: msg/sec per queue |
| Payload Size Limit | Default 1 MB (message.max.bytes); larger is anti-pattern | 256 KB (requires AWS S3 Extended Client) | Configurable (typically capped at 128 MB; memory-intensive) |
| Primary Sweet Spot | Event streaming, CDC, multi-consumer fanout, audit pipelines | Decoupled background task queues, URL crawlers, burst absorption | Complex AMQP routing, transactional RPC, microservice task dispatch |
When to Choose Kafka vs SQS / RabbitMQ in Interviews
Mental Model: Message Queue vs Event Stream
1. Choose a Message Queue (SQS / RabbitMQ) when:
- Workloads are Task-Oriented: Each task needs to be performed exactly once by any available worker in a worker pool.
- Failures are Independent (No Head-of-Line Blocking): If Worker A encounters an error processing Task #12, Task #13 and #14 must continue immediately without waiting.
- Native Retries & DLQ are Required: You want out-of-the-box exponential backoff, visibility timeouts, and dead-letter queue routing without writing custom broker topology code.
- Complex Routing is Required: You need AMQP Topic wildcard exchanges (e.g.
order.europe.electronics.*) or headers exchanges (RabbitMQ).
2. Choose an Event Stream (Kafka) when:
- High Ingestion Throughput is Paramount: Hundreds of thousands or millions of events per second (e.g. telemetry, clickstreams, sensor logs).
- Multiple Independent Consumer Groups (Fan-Out): Multiple downstream microservices need to read the identical event stream at their own independent speeds without replicating data (e.g. FB Live Comments: UI stream, toxicity moderation, ML analytics).
- Strict FIFO Ordering per Entity is Required: You must guarantee that all events for a given entity are processed in exact arrival sequence (e.g. Ticketmaster virtual waiting queue, bank ledger transactions).
- Event Replayability is Required: Consumers must be able to rewind offsets to re-process historical data after a bug fix, train ML models, or rebuild materialized views.
- Real-Time Stream Processing: Integration with stream processing frameworks (Kafka Streams, Apache Flink) for sliding or tumbling window aggregations (e.g. Ad Click Aggregator).
Deep Dive: The Web Crawler Case Study (SQS vs Kafka)
A classic system design interview question is: "Why would you use AWS SQS instead of Kafka for a distributed Web Crawler?"
In a web crawler, workers fetch billions of web pages. URLs from different hosts have radically different latencies, rate limits, transient network errors (DNS timeouts, HTTP 429, HTTP 503), or permanently dead links (HTTP 404).
Why Kafka Suffers from Head-of-Line Blocking in Web Crawlers:
Topic: "crawl-urls" | Partition 0
[ URL 1: Fast ][ URL 2: 503 Timeout (Blocked) ][ URL 3: Fast ][ URL 4: Fast ]
▲
│ Consumer blocked / sleeping in-place
│ Records 3 & 4 CANNOT BE PROCESSED!
Why AWS SQS Excels for Web Crawlers:
[ URL 1 ] ──> Worker 1 (Succeeds)
[ URL 2 ] ──> Worker 2 (Times out ➔ Visibility Timeout expires ➔ Requeued automatically)
[ URL 3 ] ──> Worker 3 (Succeeds immediately)
[ URL 4 ] ──> Worker 4 (Succeeds immediately)
- Kafka's Partition Cursor: Each partition is assigned to one consumer thread. If URL 2 times out or fails, the consumer cannot simply commit offset 3 and leave 2 uncommitted. If it pauses or retries locally, the entire partition stops processing, creating catastrophic consumer lag.
- SQS's Visibility Timeout: Worker 2 attempts URL 2 and encounters a 503. SQS makes URL 2 invisible for 30 seconds. In the meantime, Workers 3 and 4 process URLs 3 and 4 with zero delay. If Worker 2 never deletes URL 2, SQS automatically makes it visible again for another worker, and eventually sends it to a DLQ after
maxReceiveCountfailures.
For uncoordinated worker task execution with independent transient failures, AWS SQS is often superior to Kafka because it avoids the complexity of building custom non-blocking retry topics.
The Large Payload Anti-Pattern & The Claim Check Pattern
A frequent pitfall in system design interviews is using Kafka to store large media files (e.g. YouTube video uploads, raw audio, high-resolution images).
Why Large Payloads Degrade Kafka
- Kafka is optimized for small messages (1 KB to 100 KB). Its performance relies on the OS Page Cache and Zero-Copy (
sendfile) network transfers. - Large messages (> 1 MB) pollute the OS page cache, cause massive JVM garbage collection pauses during producer/consumer buffer allocation, trigger frequent socket timeouts, and drastically reduce broker throughput.
The Solution: Claim Check Pattern
Claim Check Architecture (e.g., YouTube Video Upload):
1. Client uploads 4K Video (2 GB)
│
▼
[ Amazon S3 / Blob Storage ] ──> Generates s3://videos/raw/abc-123.mp4
│
▼ 2. Publish metadata pointer (1 KB)
[ Kafka Topic: video-uploaded ]
{ "videoId": "v-99", "s3Uri": "s3://..." }
│
▼ 3. Transcoding workers poll pointer
[ Transcoding Worker Pool ]
│
▼ 4. Stream chunks directly from S3
[ Amazon S3 ]
- The client uploads the large video directly to distributed object storage (Amazon S3 or Google Cloud Storage) via a presigned URL.
- Once the blob is durable, the API service publishes a lightweight event (typically < 1 KB) to Kafka containing the metadata and S3 URI pointer.
- Downstream transcoding workers consume the Kafka event and stream the video chunks directly from S3.
Single-Broker Sizing Heuristics for System Design Interviews
When an interviewer asks: "How many Kafka brokers do we need for this system?", apply these principal engineering sizing heuristics:
Broker Sizing Estimator:
1. Message Throughput: 1 broker can comfortably handle ~1,000,000 messages/sec (or 50–100 MB/sec disk write bandwidth).
2. Disk Capacity: Modern broker node typically provisioned with 1 TB to 10 TB of NVMe SSD storage.
3. Retention Calculation:
Storage Required = Daily Ingestion Volume (GB) × Retention Days × Replication Factor (typically 3)
Numerical Walkthrough: Ad Click Aggregator
- Traffic: 100,000 ad clicks per second.
- Message Size: 500 bytes per click event.
- Network Ingestion Rate: .
- Daily Raw Data: .
- With Replication Factor = 3 & 7-Day Retention:
- Broker Count:
- Storage bottleneck: .
- Throughput bottleneck: write bandwidth .
- Decision: Provision a 20-broker cluster (storage-bound) with at least 40–60 partitions per topic to distribute load evenly.
Production Gotchas: "What if Kafka Goes Down?"
In system design interviews, candidates often panic when asked: "What happens if Kafka goes down?"
Push back gently on the premise. Kafka is always available, sometimes consistent under standard distributed systems operation. A production Kafka cluster runs across multiple availability zones (AZs) with:
- Partition Replication: A replication factor of 3 (1 Leader + 2 Followers) distributed across separate physical racks/AZs.
- Quorum Consensus (KRaft): Active controller failover in milliseconds without split-brain risk.
- In-Sync Replicas (ISR): Automatic leader election if a broker node fails.
The realistic failure domain in Kafka is not entire cluster downtime; it is:
- Broker Hardware Failure: Automatically mitigated by promoting an in-sync follower to partition leader.
- Consumer Crashes & Poison Pills: Mitigated by non-blocking retry topics and consumer group rebalances.
- Producer Network Partition: Mitigated by idempotent producer retries (
enable.idempotence=true) and buffering in theRecordAccumulator.
Production Post-Mortem: Why Using Kafka as a Long-Running Job Queue Triggers Rebalance Storms
A common architectural anti-pattern occurs when a team already has Kafka deployed and decides: "We already run Kafka—let's push our 10-minute CSV export / video transcoding / LLM batch jobs into a Kafka topic instead of provisioning SQS or RabbitMQ."
1. Ontology Mismatch: An Event Is Not a Job
| Dimension | Event Stream (Kafka's Native DNA) | Background Job (Work Queue DNA) |
|---|---|---|
| Semantics | An immutable fact that already happened (OrderCreated). | A command / unit of work waiting to be executed (GenerateAnnualReport). |
| Progress Tracking | Single Contiguous Offset Watermark (committedOffset): Committing offset 50 declares that every record 0..49 is finished. | Per-Message Independent Lifecycle: Job #2 can run for 15 minutes while Jobs #3..#100 finish in 100ms and are individually ACKed. |
| Execution Duration | Microseconds to a few milliseconds per record; optimized for batching (max.poll.records=500). | Highly variable (100ms to 30 minutes); zero benefit from batching (max.poll.records=1 disables Kafka's batching advantage). |
| Concurrency Scaling | Locked to Partition Count (12 partitions = max 12 active workers in a consumer group). | Scales elastically to hundreds of competing workers without repartitioning storage. |
2. Anatomy of the 10-Minute Export Rebalance Storm (Kafka 3.x)
Suppose a topic export-jobs has 6 partitions, max.poll.interval.ms = 300000 (5 minutes), and Worker 1 picks up a large tenant export that takes 8 minutes:
- At : Worker 1 is still streaming rows to S3 and has not called
poll(). Its background heartbeat thread detectsmax.poll.interval.msexpired and sendsLeaveGroupto the broker. - Partition Revocation: The Group Coordinator triggers a rebalance and reassigns Partition 0 to Worker 2.
- Zombie Duplicate Execution: Worker 1 is still running the 8-minute export (burning DB CPU and S3 bandwidth!), while Worker 2 fetches the exact same uncommitted export job and starts a second 8-minute export in parallel!
- Cascade to Zero Throughput: At , Worker 1 finishes and calls
commitSync(), which throwsCommitFailedException(fenced bygenerationId). Meanwhile, Worker 2 also exceeds 5 minutes at , handing the job to Worker 3. Effective cluster throughput drops to zero while database load multiplies!
3. Why the 3 Standard Kafka Workarounds Still Hurt
- Workaround A: Crank
max.poll.interval.msto 30 Minutes (+ Static Membershipgroup.instance.id)- Why it hurts: In Kafka,
max.poll.interval.msis both your maximum allowed job time and your hung-worker detection timeout. Setting it to 30 minutes creates a 30-minute blind window: if a worker deadlocks on a socket at minute 1, that partition sits completely frozen for 29 minutes before another worker can take over! Furthermore, KubernetesStatefulSet(group.instance.id) only suppresses rebalances during pod restarts—it still leaves the partition unconsumed duringsession.timeout.ms.
- Why it hurts: In Kafka,
- Workaround B: Set
max.poll.records = 1- Why it hurts: Throws away Kafka's batching throughput while keeping concurrency hard-capped by partition count. If 4 out of 6 partitions get stuck on 10-minute jobs, 1,000 tiny 1-second jobs sitting behind them experience massive Head-of-Line (HoL) blocking.
- Workaround C:
consumer.pause()+ Worker Pool + ManualTreeMap<Long, Boolean>Watermark Tracking- Why it hurts: You can pause partitions, keep calling
poll(Duration.ZERO)every 100ms to satisfymax.poll.interval.ms, and dispatch jobs to aThreadPoolExecutor. However, because Kafka only stores a single contiguous offset watermark, if Joboffset=10takes 10 minutes while Jobs11..50finish in 1 second, you must maintain an in-memoryTreeMap<Long, Boolean> inFlightand cannot commit offsets11..50until10finishes! If the pod crashes at minute 9, Jobs11..50are re-executed from scratch.
- Why it hurts: You can pause partitions, keep calling
4. How SQS / RabbitMQ Solve Long-Running Jobs Cleanly (ChangeMessageVisibility)
In AWS SQS, visibility timeout and job duration are decoupled via per-message heartbeating:
- Configure a short
VisibilityTimeout = 60 secondson the SQS queue. - While a worker streams a 15-minute export (e.g., after every 50,000 rows), the worker calls
ChangeMessageVisibility(receiptHandle, 60)to extend the lease on that specific message by another 60 seconds. - Result: A 15-minute job runs to completion with zero timeout errors, and if the worker crashes or deadlocks at any point, SQS detects the missing heartbeat and reassigns the job within 60 seconds (no 30-minute blind window!).
Kafka 4.x Share Groups (KIP-932): Now That Kafka Has a Real Queue, Should You Use It as a Work Queue?
With KIP-932 (Queues for Kafka / Share Groups)—Preview in Kafka 4.0, Beta in 4.1, and GA in Kafka 4.2—Kafka introduced KafkaShareConsumer to address competing-consumer queue workloads natively inside a Kafka topic.
1. What Share Groups (KafkaShareConsumer) Actually Solve
- Breaks the Partition Concurrency Ceiling: Multiple consumers in the same Share Group can read records from the same partition concurrently (e.g., 50 worker pods pulling jobs from a 6-partition topic).
- Per-Record Individual Acknowledgement (
AcknowledgeType): Instead of a single contiguous watermark, the broker tracks an In-Flight Record State Window (AvailableAcquiredAcknowledged/Archived):ACCEPT: Job succeeded (mark acknowledged).RELEASE: Transient failure; return record toAvailableimmediately for another worker.REJECT: Unrecoverable error; archive/route without blocking subsequent records.RENEW(added in Kafka 4.2): Heartbeat/extend the acquisition lock timeout (group.share.record.lock.duration.ms, default30s) for long-running jobs—just like SQSChangeMessageVisibility!
- Combined with KIP-848 (
group.protocol=consumer): Eliminates classic stop-the-world rebalance storms by moving assignment calculation to the broker.
2. Why You STILL Shouldn't Replace a Work Queue (RabbitMQ / SQS / BullMQ) with Kafka Share Groups
Even with KIP-932, a Share Group is a queue layer bolted onto an append-only log, carrying fundamental trade-offs:
- You Sacrifice Ordering & Replayability: Share Groups explicitly give up partition ordering and arbitrary offset rewind—the two main reasons to use Kafka in the first place.
- Missing Core Work-Queue Primitives:
- No Delayed / Scheduled Jobs: Cannot natively say "run this job in 15 minutes" or "exponentially back off retry #3 by 4 minutes" (requires external delay topics or schedulers).
- No Priority Queues: Cannot jump a
VIPuser's export ahead of 50,000 queued free-tier jobs without maintaining separate topics. - No Per-Message TTL or Job Cancellation / Lookup by ID: Because storage is an immutable log segment, you cannot delete or cancel a specific queued job ID in without waiting for a worker to pull and skip it.
- The 3 Real-World Upgrade Barriers to KIP-932:
- Barrier 1 (ZooKeeper KRaft): Kafka 4.0 completely removed ZooKeeper; clusters still on ZooKeeper must complete a full KRaft migration first.
- Barrier 2 (Kafka 4.2 Broker Upgrade): Production-ready Share Groups (including
AcknowledgeType.RENEWfor long jobs) require upgrading brokers to Kafka 4.2+. - Barrier 3 (Client API Rewrite & Polyglot Gap): Share Groups do not work by flipping a config on
KafkaConsumer—you must rewrite consumer code to the newKafkaShareConsumerAPI. Furthermore, non-Java ecosystems (librdkafkafor Go, Python, .NET) lag behind the Java client in Share Group feature parity.
[!IMPORTANT] Principal Architectural Rule of Thumb:
- Use Kafka (Consumer Groups): When publishing Domain Events (
OrderPlaced, CDC, telemetry) that require fan-out across multiple services, strict entity ordering, high batch throughput, or historical replay.- Use Kafka Share Groups (KIP-932): Only when your team is 100% JVM on Kafka 4.2+ and needs simple competing-worker parallelism on an existing event stream without operating a second broker.
- Use a Dedicated Work Queue (SQS / RabbitMQ / Redis BullMQ): Whenever you are executing stateful background jobs (exports, emails, webhooks, AI/LLM pipelines) that need per-job heartbeats, delayed retries, priority routing, job cancellation, or polyglot workers.
Senior/Staff Interview Playbook: How to Ace Kafka vs. Work Queue (SQS / RabbitMQ) Interviews
When an interviewer asks "Can we use Kafka for our background job processor / web crawler / notification retries?", a mid-level candidate debates raw throughput numbers. A Principal Engineer immediately contrasts Contiguous Offset Watermarks vs. Per-Message State Machines, explains the max.poll.interval.ms blind-window vs. rebalance-storm dilemma, and demonstrates up-to-date mastery of Kafka 4.x Share Groups (KIP-932) and their boundaries.
1. The 60-Second Senior Framing Strategy
- Distinguish Events from Jobs: Frame Kafka as an append-only distributed commit log optimized for ordered event streams, fan-out, and replay, versus SQS/RabbitMQ as ephemeral state-tracked task queues optimized for independent per-job lifecycles.
- Expose the Offset Watermark Constraint: Explain that classic Kafka tracks progress via a single integer watermark per partition. If Job #1 takes 10 minutes and Jobs #2–#100 take 10ms, Kafka either blocks Jobs #2–#100 (Head-of-Line blocking) or risks duplicate execution of #2–#100 if the worker crashes before #1 completes.
- Highlight the Timer Coupled Trade-off: Contrast Kafka's single
max.poll.interval.ms(which couples max job duration with dead-worker detection time) against SQS's decoupledVisibilityTimeout+ChangeMessageVisibilityheartbeat pattern. - Proactively Address Kafka 4.x (KIP-932): Show architectural currency by noting that while Kafka 4.2 Share Groups (
KafkaShareConsumer) add per-recordACCEPT/RELEASE/REJECT/RENEWACKs, they still lack delayed scheduling, priority queues, and job cancellation—making purpose-built queues superior for rich job orchestration.
2. Classic Interviewer Traps & Principal Rebuttals
Trap 1: "Our 10-minute export jobs on Kafka keep triggering rebalances and running twice. Why don't we just set max.poll.interval.ms = 3600000 (1 hour) and max.poll.records = 1?"
- Junior/Mid Answer: "Yes! Setting
max.poll.interval.msto 1 hour gives the job plenty of time to finish, andmax.poll.records = 1ensures we only fetch one job at a time." - Principal Rebuttal: *"That patch trades a rebalance storm for two severe operational vulnerabilities:
- The 1-Hour Blind Window: In Kafka,
max.poll.interval.msis how the broker detects a hung application thread (e.g., deadlocked or stuck on an unclosed socket while the JVM heartbeat thread stays alive). Setting it to 1 hour means a hung worker freezes its entire partition for 60 minutes before failover! - Partition-Locked Concurrency & HoL Blocking: With
max.poll.records = 1, concurrency is hard-capped by partition count, and one 40-minute export blocks every 2-second export queued behind it on that partition. In contrast, AWS SQS uses a 60-secondVisibilityTimeoutpaired with periodicChangeMessageVisibilityheartbeats from the worker—allowing a 1-hour job to run safely while still detecting a deadlocked worker within 60 seconds."*
- The 1-Hour Blind Window: In Kafka,
Trap 2: "What if we keep max.poll.interval.ms small by calling consumer.pause(), handing the job to a background thread pool, and calling consumer.poll(Duration.ZERO) every 100ms?"
- Junior/Mid Answer: "That solves it completely because
poll(0)resetsmax.poll.interval.mswithout fetching new records." - Principal Rebuttal: *"While
pause()+poll(Duration.ZERO)prevents the rebalance storm, it hits two subtle traps:- Silent Auto-Commit Data Loss: If
enable.auto.commit=truewas left on,poll(Duration.ZERO)still executesmaybeAutoCommitOffsetsAsync()after 5 seconds—committing the job's offset while the worker thread is still at 1% progress! - The Contiguous Watermark Trap: If your worker pool processes 10 jobs concurrently from the same partition and Job
offset=100takes 15 minutes while Jobs101..109finish in 1 second, you cannot commit offset110until100finishes! You have to build an in-memoryTreeMapwatermark tracker, and if the pod dies at minute 14, Jobs101..109will execute a second time upon restart."*
- Silent Auto-Commit Data Loss: If
Trap 3: "Didn't Kafka 4.0+ add Share Groups (KIP-932) so Kafka has a real queue now? Doesn't that make RabbitMQ and SQS obsolete?"
- Junior/Mid Answer: "Yes, Kafka 4.0 added queues so you don't need RabbitMQ or SQS anymore."
- Principal Rebuttal: *"KIP-932 (
KafkaShareConsumer, GA in Kafka 4.2) is a major leap: it adds competing consumption within a single partition and per-recordACCEPT,RELEASE,REJECT, andRENEWacknowledgements. However, it does not replace full-featured work queues for three reasons:- It sacrifices ordering and offset replay, turning Kafka into a basic FIFO dispenser.
- It still lacks native delayed/scheduled delivery (e.g., backoff 10 minutes), message priorities, per-message TTL, and job cancellation.
- It requires KRaft, Kafka 4.2+ brokers, and rewriting consumer code to
KafkaShareConsumer(which still lacks full parity in non-JVMlibrdkafkaclients). For rich background job lifecycles, a dedicated queue or hybrid Kafka (Events) Worker Queue (Jobs) architecture remains cleaner."*
3. Mid-Level vs. Principal Candidate Cheat Sheet
| Concept / Scenario | Mid-Level Candidate Says | Principal Candidate Demonstrates |
|---|---|---|
| Core Difference | "Kafka keeps messages on disk; RabbitMQ deletes them." | "Kafka tracks a single contiguous partition offset watermark for ordered event streams; queues track per-message state machines (Available/In-Flight/Acked)." |
| Long-Running Jobs (10+ min) | "Increase max.poll.interval.ms to 30 minutes." | "Increasing max.poll.interval.ms creates a 30-min blind window for hung threads; use SQS VisibilityTimeout + ChangeMessageVisibility heartbeats or hybrid Status Store + Work Queue." |
Static Membership (group.instance.id) | "Static membership prevents all rebalances." | "Requires StatefulSet stable identities and suppresses rebalances during brief restarts, but leaves the partition unconsumed for the entire session.timeout.ms window." |
| Kafka 4.x Share Groups (KIP-932) | "Never heard of it" or "It replaces SQS completely." | "Introduces KafkaShareConsumer with per-record ACCEPT/RELEASE/REJECT/RENEW and intra-partition concurrency, but lacks delayed jobs, priority routing, and replay." |
