Mastering Service Interaction: Protocols, Discovery, and Resilience in Microservices
This article explores best‑practice patterns for microservice communication, covering synchronous and asynchronous protocols, serialization formats, API design, service discovery, versioning, rate limiting, circuit breakers, correlation IDs, distributed consistency, authentication, retries, and economic considerations.
Service Interaction
Microservice architectures consist of many small, single‑purpose services that must interact reliably. This article discusses the challenges and solutions for service communication.
Communication Protocols
Because services may be written in different languages, the transport protocol must be language‑agnostic and support both synchronous and asynchronous patterns.
Transport protocols : HTTP is the default choice for synchronous calls, offering broad client support, built‑in load balancing, caching, compression, authentication, and a mature tooling ecosystem. HTTP/2 improves on HTTP/1.1 by compressing headers and multiplexing requests over a single persistent connection.
For asynchronous communication, a publish‑subscribe model is recommended, implemented either via a message broker or service‑provided webhooks . Brokers centralize delivery but can become a single point of failure, so they must be fault‑tolerant and horizontally scalable. Webhooks avoid a central broker and can be built into service templates.
Serialization Formats
The two dominant formats are JSON (text‑based, widely supported) and Protocol Buffers (binary, more efficient). JSON is easy to adopt but repeats field names, increasing payload size; compression can mitigate this. Protocol Buffers offer higher performance and smaller messages but require shared .proto definitions and code generation.
Defining Service Exceptions
Standardize error handling using HTTP status codes: 2xx for success, 4xx for client errors, and 5xx or timeouts for service failures. Load balancers and reverse proxies can surface backend failures as 502/503.
API Design
Good APIs are resource‑oriented, self‑descriptive, and evolve with minimal impact on consumers. Combine HTTP with RESTful principles (GET, POST, PATCH, etc.) to expose rich resources and benefit from extensive tooling.
Service Discovery
Hard‑coded IPs are impractical; a service registry acts as the authoritative source of available services and their network locations. Services can register themselves (self‑registration) or be registered by external monitors. Discovery can be performed by intelligent servers (load balancers) or intelligent clients (e.g., Netflix Ribbon) that query the registry directly.
Decentralized Interaction
Complex workflows can be coordinated either by a centralized orchestrator (synchronous, single point of logic) or by decentralized interaction where each service autonomously reacts to events, enabling weak coupling and high cohesion.
Versioning
APIs must support versioning to manage change. Maintaining multiple versions within a single service instance using a versioning scheme avoids the overhead of separate services while keeping backward compatibility.
Rate Limiting
Overloaded services should fail fast. Apply request limits and dynamic throttling to protect downstream services, especially for non‑auto‑scaling components.
Connection Pools
Use per‑service connection pools to smooth traffic spikes and isolate downstream failures. When a pool is exhausted, fail fast to signal upstream services.
Shorter Timeouts
Configure downstream call timeouts based on expected latency (e.g., 500 ms for a 10‑50 ms service) to prevent cascading delays.
Tolerating Unrelated Changes
APIs should be resilient to additive or non‑breaking field changes, allowing independent evolution without coordination.
Circuit Breaker
Implement a circuit breaker that temporarily halts calls to a failing service after repeated errors, periodically probing for recovery.
Correlation ID
Attach a unique identifier (e.g., UUID) to each request to trace its path across services when combined with centralized logging.
Maintaining Distributed Consistency
Achieve eventual consistency by publishing events to a feed that other services consume. When strong consistency is required, co‑locate data in a single service/database or use distributed transactions as a last resort.
Authentication
All API calls must be authenticated, typically via unique API keys managed centrally or through a platform‑wide identity service.
Automatic Retries
After fast‑fail, retry transient failures with exponential backoff and jitter to avoid thundering‑herd effects. Persistently failing requests should be sent to a dead‑letter queue for analysis.
Enforcing API‑Only Communication
Services must communicate exclusively through defined APIs; direct database access between services indicates a design flaw.
Economic Considerations
Track the true cost of consuming other services by issuing service invoices that include development, infrastructure, and third‑party usage fees, enabling teams to make cost‑aware decisions.
Client Libraries
Encapsulate common concerns—discovery, authentication, circuit breaking, connection pooling, and timeouts—in reusable client libraries with sensible defaults, while keeping business logic out of the library.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
