Microservice Architecture Patterns
Design microservices using proven architecture patterns — decomposition strategies, communication patterns, and data management for distributed systems.
Microservice Design Principles
Microservices decompose a large application into small, independently deployable services, each owning its domain logic and data. Key design principles: Single Responsibility (each service does one thing well — OrderService manages orders, InventoryService manages stock), Database per Service (each microservice has its own database — no shared databases, enabling independent scaling and technology choice), API First (design API contracts before implementation — OpenAPI specs define the interface), Bounded Contexts (from DDD — each service is a bounded context with its own ubiquitous language), and Decentralized Governance (each team chooses their own tech stack, deployment cadence, and data store). The trade-offs are real: microservices add network latency, distributed debugging complexity, eventual consistency challenges, and operational overhead. Start with a well-structured monolith and extract services only when you have specific scaling, team, or technology needs.
Communication Patterns
- REST/HTTP: The default for synchronous communication — simple, well-understood, cacheable. Use for user-facing APIs and query operations
- gRPC: High-performance RPC framework — binary protobuf serialization, HTTP/2 multiplexing, bidirectional streaming. 7-10x faster than JSON/REST. Use for internal service-to-service
- Message Queues (RabbitMQ): Async point-to-point — producer sends message to queue, one consumer processes it. Decouples services, handles backpressure
- Event Streaming (Kafka): Publish-subscribe event log — producers publish to topics, multiple consumers read independently. Event sourcing, audit trail, replayability
- API Gateway (YARP/Ocelot): Single entry point for external clients — routing, authentication, rate limiting, response aggregation. Hides internal service topology
- Service Mesh (Istio/Linkerd): Infrastructure-level communication — mTLS, retries, circuit breaking, observability without changing application code
Data Management Patterns
- Database per Service: Each service owns its data — OrderService uses PostgreSQL, ProductService uses MongoDB, SearchService uses Elasticsearch
- Saga Pattern: Distributed transactions across services — Choreography (event-driven, each service reacts) or Orchestration (coordinator manages the flow)
- CQRS + Event Sourcing: Separate write models (event store) from read models (materialized views) — rebuild state from event history, multiple read projections
- Outbox Pattern: Reliably publish events when data changes — write event to outbox table in same transaction as data change, background process publishes events
- API Composition: Aggregate data from multiple services at the API gateway or a dedicated aggregation service — replaces database joins across services
- Change Data Capture (CDC): Debezium/CDC captures database changes and publishes them as events — no code changes needed, reliable event publishing