I. Introduction
A microservices architecture is a distributed system: a collection of independent nodes separated by a network; this “separation” is what gives microservices their flexibility.
However, it also means every interaction between services crosses a boundary that can be slow, unreliable, or unavailable.
Misunderstanding how services communicate across that boundary is one of the immediate ways to cause severe production problems.
That’s why this article walks through the fundamentals of distributed communication, compares the two dominant styles (RPC and message-driven), and covers how to evolve services without breaking the ones that depend on them.
II. The Two Forces That Shape Everything: Latency and Availability
Network Latency
Network latency is the time it takes for data to travel from one node to another and for the response to come back: one full request-and-response cycle.

Here are a few points to keep in mind:
- It is measured in milliseconds. Even on the same local network, it is fast, but it is never free.
- Compare it with memory access: a network call costs milliseconds, while reading from RAM costs nanoseconds. That is a difference of roughly six orders of magnitude.
- Raw network time is only part of the story. Processing time on the receiving service adds to what the caller experiences.
- Because a single user action can fan out into many calls, latency has a large impact on overall microservices performance.
Availability
The question “Does the service respond to requests?” is addressed by availability.
It is expressed as a percentage, and assuming 100% is risky.
Networks drop packets, instances restart, and deployments fail.
It is important to prepare for communication breakdowns from the beginning rather than treating them as an afterthought.

III. How Dependencies Compound
When services depend on one another, their characteristics combine in ways that are easy to underestimate.
Latency is additive
Latency is additive when the caller must wait for the total of those latencies if service A calls B, which calls C, which calls D.

Availability is multiplicative
A’s effective availability is roughly Availability(B) x Availability(C) x Availability(D) if A depends on B, C, and D. In the decent scenario, three services at 99.9% each give you roughly 99.7%, and the number decreases with each additional dependency.

These effects cascade. Slow services slow down everything that depends on them, and errors in one service reduce the availability of its dependents.
Timeouts and retries are the usual first line of defense, but there are no easy answers here.
Certain tactics can make things worse: aggressive retries against a service that is already struggling can turn a slowdown into an outage. For anyone running microservices at scale, latency and availability are the main issues, so make sure to account for them.
IV. RPC Communication
When dependency relationships between services are comparatively stable over time, Remote Procedure Call (RPC) communication performs best.
gRPC service methods and REST endpoints are examples of common forms.
Why choose gRPC or a similar RPC approach?
Simplicity
Only two actors are involved: a client and a server.

Clear fit
It works well when availability is high and latency is low, or when higher latency is tolerable.

Stable relationships.
When it is clear which service calls which, a direct request-and-response model is easy to reason about and debug.
The tradeoff is tight runtime coupling: the caller needs the callee to be up and reasonably fast at the moment of the call.
V. Service Discovery
Services must be able to learn how to communicate with each other in a changing environment. Hard-coded addresses are not resilient to failover, redeployments, or scaling.
DNS-based service discovery
The simplest approach: given a service’s name, DNS dynamically returns the IP address for that service.
Kubernetes has built-in support for DNS-based discovery, and major cloud providers offer their own equivalents.
Service meshes
If you are in a more complex environment, like multi-region, multi-cloud, or hybrid networks, you often need more: load shifting, failover, A/B testing, canary releases, security, and observability.
Service mesh tools such as Istio and Consul, along with platforms like OpenShift and Rancher, address these needs.
A service mesh is not free, so weigh the trade-offs honestly:
- Does it have the features you need, and does it solve problems you actually have today? Be cautious about adopting it for problems you might have in the future.
- Do the benefits outweigh the cost in complexity and operational overhead?
V. Message-Driven Architecture
Message-driven architecture goes by several names: event-driven architecture, message-oriented architecture, and publish-subscribe (pub/sub).
Instead of calling a service directly, a producer publishes a message and moves on.
RPC versus message-driven
| RPC | Message-driven | |
| Participants | Single client, single server | Messages routed to any number of consumers |
| Interaction | A pair of messages: request and response | Published in a “fire and forget” manner |
Advantages over RPC
Eliminates cascading effects
The publisher does not wait on consumers, so downstream latency and availability problems do not propagate back to it.
Encourages loose coupling
The publisher does not know who receives the message.
Handles sudden increases in traffic
In the meantime, messages are queued temporarily, and queue length becomes a useful operational metric.
Distributed transactions
Represents the in-progress details of an activity coordinated across multiple systems and may provide these capabilities at least once.
Workflows that span services now require careful attention to:
- message routing
- visibility and observability, so you can trace what happened across services
- failure compensation, since you cannot simply roll back across service boundaries
VI. Managing Dependencies Without Losing Independence
Independent services are the main goal of microservices; dependencies are unavoidable. That’s why the challenge is to manage them without eroding that independence.
API versioning

The real threat is breaking changes; that’s why API versioning lets a service publish changes without breaking other services or requiring coordinated deployments. The cost is that you must maintain multiple versions at once. That is the price of service independence.
When retiring older versions, deprecate deliberately: issue warning messages, and prioritize getting consumers to upgrade.
Versioning in message-based systems
If content changes over time, breaking changes may arise.
Two common solutions:
- Version the topic name, for example, user.created.v2.
- Version the message content, for example, { “version”: “2.0”, “message”: … }.
Versioning and deprecation discipline
Be intentional about what you publish, because you may be stuck with those decisions for a long time. Apply consistent versioning and deprecation rules across all services. Inconsistency leads to bad decisions and creates the danger of downtime.
Summary
There you have it; in this post, we have described how a microservices system is a distributed system, which means the network is an essential part of your architecture.
Latency can accumulate across multiple service dependencies, and overall availability decreases as you add more dependencies, so it is important to design for failure.
Moreover, we discussed synchronous communication, which, through RPC protocols such as REST and gRPC, is straightforward and effective for steady, well-understood service relationships.
However, message-driven architecture (asynchronous communication) can reduce coupling and help prevent cascading failures, although it introduces additional challenges in transaction management and observability.
Lastly, for service discovery, we started with DNS-based discovery. We considered adopting a service mesh only when its capabilities justify the added complexity, establishing consistent versioning strategies for both APIs and messages, and carefully managing deprecation to ensure smooth transitions without disrupting dependent services.
Until next time, happy programming!
Please don’t forget to bookmark, like, and comment. Cheers! And thank you!

Leave a Reply