Home/Learn/System Design/Microservices Architecture

Microservices Architecture

Intermediate
Architectural Patterns

Microservices decompose a system into small, independently deployable services, each owning a specific business capability. They enable team autonomy, independent scaling, and technology flexibility at the cost of distributed-systems complexity.

Overview

Microservices architecture structures an application as a collection of loosely coupled services, each responsible for a distinct business capability (e.g. User Service, Order Service, Payment Service). Each service has its own database (database-per-service), is deployed independently, and communicates via APIs (REST, gRPC) or events (Kafka). This enables small teams to own, develop, and deploy services independently with their own release cycles. Services can be scaled individually — the search service can have 50 instances while the admin service has 2. Technology choices are per-service — one team might use Java, another Python. The trade-offs are significant: distributed transactions (no single DB commit), inter-service communication overhead, debugging complexity (distributed tracing needed), and operational overhead (you now manage dozens of deployments). Microservices are not a default — they are adopted when the organisational and scaling benefits outweigh the distributed-systems complexity.

Monolith vs Microservices

A monolith deploys all functionality as a single unit. Microservices split functionality into independently deployable services. Start monolith, migrate to microservices when team/scale demands it.

Conceptual — monolith vs microservices
// Monolith — single deployable unit
// ┌─────────────────────────────────┐
// │           Monolith               │
// │  ┌──────┐ ┌──────┐ ┌──────┐    │
// │  │Users │ │Orders│ │Pay   │    │
// │  │Module│ │Module│ │Module│    │
// │  └──┬───┘ └──┬───┘ └──┬───┘    │
// │     └────────┴────────┘         │
// │         Shared Database         │
// └─────────────────────────────────┘

// Microservices — independent services
// ┌──────────┐  ┌──────────┐  ┌──────────┐
// │ User Svc  │  │ Order Svc │  │ Pay Svc   │
// │ (Java)    │  │ (Java)    │  │ (Go)      │
// └─────┬────┘  └─────┬────┘  └─────┬────┘
//       │             │             │
//   Users DB      Orders DB     Payments DB
//  (PostgreSQL)  (PostgreSQL)    (DynamoDB)

// Communication:
// Sync: REST / gRPC (request-response)
// Async: Kafka / SQS (event-driven)

Key Principles

Each service owns its data (no shared database), has a bounded context (DDD), communicates via well-defined APIs, and can be deployed independently. Conway's Law applies — structure services around team boundaries.

Java + Conceptual — microservices principles
// Key microservices principles:

// 1. Single Responsibility — one business capability per service
// UserService: registration, profile, authentication
// OrderService: order creation, status, history
// PaymentService: charge, refund, billing

// 2. Database per service — no shared tables
// UserService → users_db (PostgreSQL)
// OrderService → orders_db (PostgreSQL)
// PaymentService → payments_db (DynamoDB)

// 3. API contract — services communicate via defined interfaces
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable String id) { ... }
}

// 4. Independent deployment
// Deploy OrderService v2.3 without touching UserService
// Feature flags for gradual rollout

// 5. Decentralised governance
// Teams choose their own tech stack, frameworks, deployment cadence

Challenges

Microservices introduce distributed-systems problems: network failures, data consistency, debugging, and operational overhead. Solve with patterns: saga, circuit breaker, API gateway, distributed tracing.

Conceptual — microservices challenges and solutions
// Challenge → Solution mapping
//
// Distributed transactions  → Saga pattern (choreography or orchestration)
// Cross-service queries     → API composition or CQRS read model
// Service-to-service calls  → Circuit breaker + retry + timeout
// Debugging distributed flows → Distributed tracing (Jaeger, Zipkin)
// Authentication             → API Gateway + JWT token propagation
// Configuration management   → Spring Cloud Config / Consul
// Service discovery          → Kubernetes DNS / Eureka / Consul
// Monitoring                 → Prometheus + Grafana + ELK stack

// When NOT to use microservices:
// ❌ Small team (< 5 developers)
// ❌ Simple domain (CRUD app)
// ❌ Startup MVP (need speed)
// ❌ No DevOps maturity (can't manage 20+ deployments)
// Start with a monolith, extract services as complexity grows

Key Points to Remember

  • 1Each microservice owns one business capability and its own database.
  • 2Services communicate via REST/gRPC (sync) or events/queues (async).
  • 3Benefits: independent deployment, team autonomy, per-service scaling, tech flexibility.
  • 4Costs: distributed transactions, debugging complexity, network overhead, operational burden.
  • 5Start with a monolith; extract microservices when team size and scale justify the complexity.

Interview Questions

Sign in to ask Aria
1

What are the advantages and disadvantages of microservices?

EasyTCS
2

What is the database-per-service pattern and why is it important?

MediumAmazon
3

When should you NOT use microservices?

MediumGoogle
4

How do you handle transactions that span multiple microservices?

HardFlipkart
5

Design the microservices architecture for a food delivery platform like Swiggy.

HardUber

Ask Aria about Microservices Architecture

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…