Service-to-service communication is one of the load-bearing decisions in a SaaS architecture. The shape of communication determines how the system behaves under load, how it tolerates failure, and how easily it can evolve. The choices ripple through four properties at once:
๐ก๏ธ
Reliability
Does the system stay stable under varying loads and failures?
โก
Performance
Request latency and throughput.
๐
Scalability
Can it grow as load and demands increase?
๐ง
Maintainability
Debuggability and ease of evolution.
The Spectrum
Synchronous
Immediate feedback, tight coupling
Caller waits for response. Simple mental model, easy to debug. Costs: tight coupling, latency propagation, cascading failures.
Asynchronous
Decoupled, fault-tolerant
Caller publishes; consumer processes when ready. Decoupled services, smoother under load. Costs: operational complexity, eventual consistency.
Real systems mix both. The skill is choosing per interaction.
Synchronous: REST APIs
HTTP REST APIs remain the foundation. Simple, debuggable, supported everywhere.
โ
Strengths
Simple to implement and debug. Universal tooling support. Immediate feedback. Clear success/failure semantics.
โ ๏ธ
Costs
Tight coupling. Latency propagation along call chains. Cascading failures.
Synchronous: GraphQL
Where GraphQL shines
Varied client needs
Mobile apps minimizing bandwidth. Complex relationship traversal. One screen needing data from many sources.
Where it bites
Operational complexity
N+1 query problems if resolvers aren't careful. Harder to cache than REST. Schema design takes effort.
Synchronous: RPC and gRPC
RPC abstracts network communication so calling a remote function looks like calling a local one. Modern implementations (gRPC) layer in strong typing, code generation, binary serialization on top of HTTP/2.
โ
Strengths
Strong contracts catch integration errors at compile time. Efficient binary serialization. Great fit for internal service comms where you control both ends.
โ ๏ธ
Costs
Browser support awkward. Opaque to humans. Requires schema management. Less universal than REST.
Asynchronous: Message Queues
Message queues decouple services by letting them exchange data without waiting for an immediate response.
01
Step 01
Send
Service A pushes a message onto the queue.
02
Step 02
Continue
A keeps working โ no blocking.
03
Step 03
Process
Service B pulls the message when it's ready.
04
Step 04
Survive failure
Messages persist when B is unavailable.
This pattern significantly improves system resilience. The cost is operational: you now have a queue to monitor, dead-letter queues to drain, consumer-lag dashboards to watch.
Asynchronous: Event Streaming
Streaming platforms like Apache Kafka provide real-time data streams where services publish events as they occur, and other services subscribe to relevant streams.
๐
Real-time analytics
Process user behavior as it happens.
๐๏ธ
System monitoring
Instrument infrastructure with structured events.
๐
Data consistency
Propagate state changes across services through events.
The key shift is publish to a log, not call a service. Producers donโt know whoโs listening; consumers can rewind, replay, and arrive late. Kafka gets a deep dive in Section 5.
Asynchronous: Pub/Sub
Pub/Sub messaging lets services broadcast events to multiple interested parties without knowing whoโs listening.
Order Service โ [purchase.completed] โ โ โ Inventory Email Analytics Service Service Service
HTTP Protocol Evolution
๐ข
HTTP/1.1
Universal support. Connection-per-request issues. Verbose plain-text headers. The compatibility floor.
Built on QUIC over UDP. No head-of-line blocking on packet loss. Best on lossy mobile networks.
For internal service-to-service on stable networks, HTTP/2 is the modern default. For client-facing on the public internet โ especially mobile โ HTTP/3 has the edge.
Bidirectional: WebSockets
WebSockets provide bidirectional persistent connections between clients and servers.
๐ฌ
Real-time chat
Instant messaging between users.
โ๏ธ
Collaborative editing
Synchronize document changes across users.
๐
Live dashboards
Push data updates without polling.
The trade-off is operational: load-balancing persistent connections is harder, connection management gets non-trivial at scale, reconnection logic needs deliberate design.
Message Delivery Guarantees
๐ป
At most once
Simple, but messages can be lost on system failures.
๐
At least once
Default for most systems. Messages can duplicate. Consumers must be idempotent.
๐
Exactly once
Theoretically perfect. Hard to implement; often unnecessary. Whole lesson on this in Section 5.
Order and Durability
No ordering
Maximum throughput
Messages processed in parallel. Workers pull freely. Right when each message is independent.
Ordered by partition
Practical compromise
Kafka partitions: strict order within a key (e.g., user ID), parallelism across keys. The right answer for most ordered workloads.
Global ordering is expensive and usually unnecessary. Most โwe need orderingโ requirements are actually โwe need ordering per entityโ โ which partition keys give you.
Choosing the Right Pattern
The most successful applications donโt rely on a single pattern. They use the right one for each specific need:
โก
Sync patterns
User-related operations needing immediate feedback and high consistency.