Kafka instead of Rest for communication between microservices
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Kafka replaces REST for microservice communication when you need asynchronous, event-driven messaging instead of synchronous request-response calls. REST works well for simple query/command interactions where the caller needs an immediate response. Kafka works better when services need to be decoupled, when event ordering matters, when throughput requirements are high, or when multiple downstream consumers need to react to the same event independently.
The choice is not binary. Most production architectures use both: REST for synchronous operations like user-facing API calls, and Kafka for asynchronous workflows like order processing, analytics pipelines, and cross-service event propagation.
How REST Communication Works Between Services
In a REST-based architecture, Service A sends an HTTP request to Service B and blocks until it receives a response:
This creates tight coupling: the Order service must know the URL of every downstream service, it blocks on each call sequentially, and if any downstream service is slow or down, the entire order placement fails or times out.
How Kafka Communication Works Between Services
With Kafka, Service A publishes an event to a topic. Any number of downstream services subscribe to that topic and process the event independently:
Each downstream service runs its own consumer:
The Order service does not know or care how many consumers exist. Inventory, Shipping, and Notification services all consume from the same topic independently.
Detailed Comparison
| Dimension | REST | Kafka |
| Communication model | Synchronous request-response | Asynchronous publish-subscribe |
| Coupling | Tight: caller knows callee's URL and API contract | Loose: producer knows only the topic name |
| Failure propagation | Downstream failure blocks or crashes the caller | Downstream failure does not affect the producer |
| Throughput | Hundreds to low thousands of requests/sec per instance | Millions of messages/sec per cluster |
| Message durability | None (unless caller retries) | Messages persisted to disk with configurable retention |
| Consumer scaling | Load balancer distributes across service replicas | Consumer groups partition work automatically |
| Ordering | No ordering guarantee across calls | Ordered within a partition |
| Replay capability | Not possible (stateless) | Consumers can rewind and replay from any offset |
| Latency | Low for single calls (milliseconds) | Slightly higher due to batching and commit (10-100 ms typical) |
| Observability | Standard HTTP status codes and tracing | Requires offset monitoring, consumer lag dashboards |
When REST Is the Better Choice
REST remains the right tool in several situations:
Synchronous query/response: When a client needs data immediately, like loading a user profile or checking account balance. The caller cannot proceed without the response.
Simple CRUD operations: For basic create-read-update-delete flows, REST's simplicity and mature tooling (OpenAPI specs, code generators, API gateways) outweigh Kafka's overhead.
External APIs: Public-facing APIs almost always use REST or GraphQL. External consumers should not need to connect to your Kafka cluster.
Low volume, low complexity: If you have five services handling a few hundred requests per second, Kafka's operational cost (ZooKeeper/KRaft, broker management, schema registry) is hard to justify.
When Kafka Is the Better Choice
Event-driven workflows: Order processing, payment settlement, fraud detection. Multiple services react to the same event independently without the producer coordinating with each one.
High throughput data pipelines: Log aggregation, clickstream processing, metric collection. Kafka handles millions of events per second with horizontal scaling.
Decoupling for resilience: If Service B goes down, Kafka retains the messages. When Service B comes back, it processes the backlog. REST would have returned errors during the downtime.
Event sourcing and replay: Kafka's durable log allows consumers to rewind to any point and reprocess events. This is valuable for rebuilding read models, debugging, or onboarding new services that need historical data.
Fan-out to multiple consumers: One event triggers reactions in five different services. With REST, the producer makes five HTTP calls. With Kafka, it publishes once and each consumer group reads independently.
Architecture Patterns
CQRS with Kafka
A common pattern separates write operations (commands) from read operations (queries). Commands go through REST to a write service, which publishes domain events to Kafka. Read services consume those events and build optimized read models:
Saga Pattern for Distributed Transactions
Long-running business processes span multiple services. Each service listens for events and publishes its own events to advance the workflow:
Each service owns its step and publishes the result. Compensating events handle rollback when a step fails.
Operational Considerations
Running Kafka in production adds operational complexity that REST does not have:
- Broker management: Kafka clusters need monitoring, scaling, and upgrades. Managed services (Confluent Cloud, AWS MSK, Redpanda Cloud) reduce this burden.
- Schema evolution: As event schemas change, producers and consumers must stay compatible. Schema Registry with Avro or Protobuf enforces compatibility.
- Consumer lag monitoring: If a consumer falls behind, its lag grows. Alerting on consumer lag is critical to detect processing bottlenecks.
- Exactly-once semantics: Kafka supports exactly-once processing, but configuring it correctly (idempotent producers, transactional consumers) requires careful setup.
Common Pitfalls
- Replacing all REST calls with Kafka. Synchronous user-facing queries still belong behind REST endpoints. Not every interaction is an event.
- Ignoring consumer lag monitoring. A consumer that falls hours behind can cause stale data, duplicate processing, or disk pressure from retained messages.
- Publishing events without a schema registry. Schema drift between producer and consumer causes silent data corruption or deserialization failures.
- Using Kafka as a database. Kafka is a durable log, not a query engine. If services need to look up current state by key, use a proper database and project events into it.
- Treating event ordering as global. Kafka guarantees ordering within a partition, not across partitions. If two events must be processed in order, they must share the same partition key.
Summary
- REST is synchronous request-response. Kafka is asynchronous publish-subscribe. Most architectures use both.
- Choose REST for user-facing queries, simple CRUD, external APIs, and low-volume interactions.
- Choose Kafka for event-driven workflows, high-throughput pipelines, service decoupling, and fan-out to multiple consumers.
- Kafka adds operational complexity (brokers, schema registry, consumer lag monitoring) that must be justified by the architectural benefits.
- The partition key determines ordering guarantees. Events that must be processed in sequence need the same partition key.
Related reading
- Kafka integration tests in Gradle runs into GitHub Actions
- Kafka INVALID_FETCH_SESSION_EPOCH
- Kafka InvalidReceiveException Invalid receive
- Kafka is failing to start. Getting the below error
- Kafka isolation level implications
- Kafka keeps rebalancing consumers
- Kafka Java API offset operations clarification
- Kafka java consumer SSL handshake Error java.security.cert.CertificateException No subject alternative names present

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.