Skip to main content

Architecture

Microservices Architecture: Communication, Resilience and Distributed Consistency

Key patterns – sync/async, Service Discovery, circuit breaker, Saga.

Microservices trade operational complexity for team autonomy and independent scaling. They succeed when domain boundaries are crisp; they fail when boundaries mirror org politics instead of coherent capabilities.

Choose synchronous APIs (REST, gRPC) when latency budgets are tight and workflows are request/response shaped. Enforce timeouts, budgets per hop, and bulkheads so one slow dependency does not exhaust thread pools.

Asynchronous messaging decouples availability and smooths spikes. Embrace at-least-once delivery semantics: design consumers idempotent with deduplication keys. Document ordering guarantees—many queues promise little; plan accordingly.

Service discovery in dynamic environments favors DNS in Kubernetes, or registraries like Consul when spanning clusters. Client-side load balancing can improve locality awareness but complicates libraries—pick one approach per ecosystem.

Resilience patterns are mandatory accessories: retries with jitter, circuit breakers, rate limiters, hedged requests for idempotent reads, and bulkheads to isolate tenants or features. Chaos testing validates assumptions before customers do.

Distributed transactions rarely scale elegantly; prefer sagas with compensating actions, outbox patterns for reliable publishing, and event sourcing where audit demands dominate. Accept eventual consistency explicitly in UX.

Data per service prevents tight coupling through shared tables, at the cost of queries spanning aggregates. Use CQRS read models or federated GraphQL cautiously—each adds teams to maintain.

Contract testing aligns producers and consumers without staging the universe. Pact-style tests or schema compatibility in CI catch breaking JSON or Protobuf changes early.

API gateways and backends-for-frontend reduce chatty mobile clients and centralize cross-cutting auth. Avoid turning gateways into mud balls of business rules—keep them thin.

Observability must stitch traces across service hops. Standardize propagation headers, log correlation IDs, and RED/USE metrics dashboards per service. Without tracing, microservices debug sessions become conference calls.

Developer experience includes local stacks: compose files, contracts, and seed data so feature dev does not require a full staging cluster on a laptop.

In summary: microservices are a socio-technical pattern—boundaries, contracts, messaging discipline, resilience, and observability must mature together. A small number of well-operated services beats dozens of orphaned repos.

Back to Knowledge Center