DevOps8 min read

Microservices Architecture

Design systems as independently deployable services - covering service boundaries, communication patterns, API gateways, service mesh, and when NOT to use microservices.

MicroservicesArchitectureAPI GatewayService MeshgRPC

skill: Microservices Architecture category: DevOps tags: [Microservices, Architecture, API Gateway, Service Mesh, gRPC] readingTime: 8

Microservices solve organizational scale problems (many teams, independent deployments) at the cost of operational complexity. For most applications and teams (< 20 engineers), a modular monolith is simpler, faster to build, and cheaper to run. Choose microservices for scale reasons, not because they sound better.

Workflow

  1. Define service boundaries with domain-driven designBad service boundaries (splitting too fine, splitting across wrong lines) create distributed monolith problems - tight coupling over the network. Bound services by business capability.
  2. Choose communication: REST vs. gRPC vs. eventsSynchronous REST is simple but creates coupling; gRPC is efficient for internal services; events decouple services and enable eventual consistency.
  3. Add an API gatewayAn API gateway is the single entry point for clients - it handles auth, rate limiting, routing, and protocol translation, so individual services don't have to.
  4. Handle distributed failures with circuit breakersIn microservices, network calls can fail. Without circuit breakers, one slow service cascades to all callers - causing system-wide failure.
  5. Implement distributed tracingA user request in a microservices system spans 5-15 services. Without tracing, diagnosing latency or errors means searching logs across all services with no clear thread.

Output Format

Microservices system: domain-based services, API gateway, async events, circuit breakers, and distributed tracing.

System Design:
├── API Gateway (auth, rate limit, routing)
├── Services (one per business domain)
│   ├── user-service (REST + JWT issuance)
│   ├── order-service (REST + publishes OrderCreated)
│   ├── payment-service (consumes OrderCreated via Kafka)
│   └── notification-service (consumes events, sends emails)
├── Message Bus: Kafka / AWS SQS+SNS
└── Observability: OpenTelemetry → Jaeger + Prometheus → Grafana

Examples

Input

Output

Edge Cases & Gotchas

  • Shared database anti-pattern - Two services sharing a database are not microservices - they're a distributed monolith. Changes to the DB schema require coordinating both services.
  • Service discovery - Hardcoded IP/hostname addresses break when services scale or restart. Use a service registry (Consul, Kubernetes DNS) so services find each other by name.
  • Event ordering guarantees - Kafka partitions guarantee ordering within a partition. For events that must be ordered (UserCreated before UserUpdated), use the same partition key (userId).
  • Versioning internal APIs - Internal gRPC or REST APIs between services also need versioning when the schema changes. Use protobuf field numbering for backward compatibility.

When to Break These Rules

  • Start with a modular monolith - same code organization as microservices but single deployment unit. Extract services only when a module needs different scaling, language, or team ownership.
  • Don't convert to microservices to solve performance problems - most performance issues in monoliths are DB, N+1 queries, or missing caches, not architectural.

Reference Files

  • https://microservices.io/patterns/
  • https://martinfowler.com/articles/microservices.html

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.