Microservices
One-line summary: Microservices split a system into small, independently deployable services aligned to business capabilities โ trading operational complexity for team autonomy and independent scaling.
๐งฉ Core Conceptsโ
Monolith vs. Microservicesโ
flowchart TB
subgraph Monolith
M[Single Deployable<br/>UI + Orders + Payments + Users]
M --> MDB[(Shared DB)]
end
subgraph Microservices
GW[API Gateway]
GW --> S1[Orders Svc] --> D1[(Orders DB)]
GW --> S2[Payments Svc] --> D2[(Payments DB)]
GW --> S3[Users Svc] --> D3[(Users DB)]
end
| Aspect | Monolith | Microservices |
|---|---|---|
| Deployment | One unit | Independent per service |
| Scaling | Whole app together | Per-service, targeted |
| Tech stack | Uniform | Polyglot allowed |
| Team autonomy | Coupled | High (own service end-to-end) |
| Data | Shared DB, easy joins/txns | DB-per-service, distributed data |
| Operational cost | Low | High (infra, observability, networking) |
| Fault isolation | Weak (one bug can crash all) | Strong (blast radius contained) |
| Local dev/debug | Simple | Complex (many moving parts) |
Start with a well-structured monolith; extract services when team size, scaling needs, or deployment friction justify the added complexity.
Service Boundaries & DDDโ
Use Domain-Driven Design to draw boundaries. Each service should own a bounded context โ a cohesive business capability with its own data. Aim for high cohesion inside a service and loose coupling between services. Avoid the distributed monolith anti-pattern (services that must deploy together).
Service Discoveryโ
Instances come and go (autoscaling, failures), so their network locations are dynamic. A service registry tracks healthy instances.
flowchart LR
S[Service Instance] -->|register / heartbeat| R[(Service Registry)]
C[Caller] -->|lookup 'orders'| R
R -->|healthy instances| C
C --> S
- Client-side discovery โ caller queries the registry and load-balances itself.
- Server-side discovery โ a load balancer / gateway resolves the target (e.g., Kubernetes Services, Consul, Eureka).
API Gatewayโ
A single entry point for clients that handles cross-cutting concerns so individual services don't have to:
- Routing & request aggregation
- Authentication / authorization
- Rate limiting & throttling
- TLS termination, caching, request/response transformation
See API Design for the contract details behind the gateway.
Inter-Service Communication: Sync vs. Asyncโ
flowchart LR
subgraph Sync[Synchronous]
A[Order Svc] -->|REST/gRPC request| B[Payment Svc]
B -->|response| A
end
subgraph Async[Asynchronous]
C[Order Svc] -->|publish event| Q[(Broker)]
Q --> D[Payment Svc]
Q --> E[Notification Svc]
end
| Synchronous (REST/gRPC) | Asynchronous (events/queues) | |
|---|---|---|
| Coupling | Temporal (both must be up) | Decoupled |
| Latency | Immediate response | Eventual |
| Failure impact | Cascades if downstream slow | Absorbed by broker |
| Best for | Query needing an answer now | Fire-and-forget, fan-out, workflows |
Prefer async messaging for workflows and fan-out (see Message Queues); use sync when the caller genuinely needs an immediate result.
๐ Saga Pattern (Distributed Transactions)โ
Without a shared database you can't use a single ACID transaction across services. A saga is a sequence of local transactions; if one step fails, compensating transactions undo the prior steps.
sequenceDiagram
participant O as Order
participant P as Payment
participant I as Inventory
O->>O: create order (pending)
O->>P: charge customer
P-->>O: charged
O->>I: reserve stock
I-->>O: out of stock (fail)
O->>P: refund (compensate)
O->>O: cancel order
- Choreography โ services react to each other's events; no central coordinator. Simple but harder to trace.
- Orchestration โ a central orchestrator drives the steps and compensations. Clearer control flow, single point to reason about.
Sagas provide eventual consistency rather than immediate atomicity โ see Consistency Models.
๐ Observabilityโ
With many services, you can't debug by reading one log file. The three pillars:
- Logging โ structured, centralized logs correlated by a trace/correlation ID.
- Metrics โ numeric time series (latency, error rate, throughput, saturation โ the RED/USE methods).
- Tracing โ distributed traces follow a request across service hops to pinpoint bottlenecks.
flowchart LR
Svc1 --> Col[Telemetry Collector]
Svc2 --> Col
Svc3 --> Col
Col --> Logs[(Logs)]
Col --> Metrics[(Metrics)]
Col --> Traces[(Traces)]
Logs & Metrics & Traces --> Dash[Dashboards & Alerts]
๐ก๏ธ Resilience Patternsโ
| Pattern | Problem it solves | How |
|---|---|---|
| Timeouts | Hanging calls tie up resources | Cap how long a call may wait |
| Retries (+ backoff + jitter) | Transient failures | Retry idempotent calls with exponential backoff |
| Circuit breaker | Cascading failures to a sick service | Trip open after N failures, fail fast, probe to recover |
| Bulkhead | One dependency exhausting all resources | Isolate pools per dependency |
| Fallback | Degrade gracefully | Serve cached/default response |
stateDiagram-v2
[*] --> Closed
Closed --> Open: failures >= threshold
Open --> HalfOpen: after cooldown
HalfOpen --> Closed: probe succeeds
HalfOpen --> Open: probe fails
Combine retries with idempotency (see API Design) to avoid duplicate side effects.
โ๏ธ Trade-offs / When to Useโ
| Adopt microservices when... | Stay monolithic when... |
|---|---|
| Multiple teams need to ship independently | Small team / early-stage product |
| Components have very different scaling needs | Domain is not yet well understood |
| You need fault isolation and polyglot stacks | Operational maturity (CI/CD, observability) is low |
| Deployment of the monolith is a bottleneck | Simplicity and low latency joins matter most |
Prerequisites: strong automation (CI/CD), containerization/orchestration, centralized observability, and clear ownership โ without these, microservices amplify pain.
Note (AI-assisted draft): The following Interview Questions, Production Checklist, and Testing & Monitoring items are a draft. Add organization-specific CI/CD links and observability dashboards as needed.
Interview Questions (expanded answers)โ
How do you decide whether to extract a component from the monolith into a microservice?โ
Decision factors:
- Business ownership: separate teams owning a capability is a strong signal.
- Scaling needs: if a component needs a different scaling profile (e.g., CPU-heavy vs I/O-light), separate it.
- Release cadence: independent deploy cycles argue for service extraction.
- Operational readiness: ensure CI/CD, observability, and incident processes exist before extracting.
If costs (operational overhead, network latency, distributed testing) exceed benefits, delay extraction or consider modular monolith patterns.
Compare choreography vs orchestration for sagas โ when is each preferable?โ
-
Choreography (event-driven): services publish events and react. Prefer when flows are naturally decoupled, event volume is manageable, and eventual consistency is acceptable. Pros: no single coordinator, easier horizontal scale. Cons: harder to debug and reason about end-to-end.
-
Orchestration (central controller): a saga orchestrator issues commands and tracks progress. Prefer when the sequence must be controlled, error handling needs centralized visibility, or business processes require strict ordering. Pros: clearer flow and observability. Cons: central point to scale/maintain.
How do you design service boundaries to minimize cross-service transactions and latency?โ
- Model around bounded contexts: group data and operations that are touched together.
- Co-locate frequently-used data; denormalize when read latency dominates and you can tolerate eventual consistency.
- Favor asynchronous messaging for long-running tasks and use request/response only where immediate answers are necessary.
- Instrument and set SLAs for inter-service calls; identify hotspots and consider API gateway-level aggregation.
Production Checklistโ
- Ensure CI/CD pipelines for each service and a global integration test workflow
- Centralize observability (traces, metrics, logs) and enforce structured logs with correlation IDs
- Harden network policies, mTLS, and service-to-service auth (e.g., SPIFFE/SPIRE)
- Automate schema and contract migrations with consumer-driven contract tests
- Maintain a shared dashboard with SLOs and error budgets per service
Testing & Monitoringโ
- Run integration tests that validate sagas and compensations end-to-end
- Simulate partial failures and validate circuit breakers and bulkheads behave correctly
- Measure cross-service latency and set SLOs per interaction
- Validate tracing propagation (trace IDs) across service boundaries under load
๐ Related Topicsโ
- Scalability โ scale individual services independently
- Load Balancing โ distribute traffic across service instances
- Consistency Models โ sagas yield eventual consistency
- Rate Limiting โ enforced at the API gateway
- Message Queues โ async backbone for inter-service events
- API Design โ the contracts services expose
โ Back to System Design ยท ยฉ sparshjaswal