What Are Microservices?
Microservices is an architectural approach where an application is built as a suite of small, independent services. Each service runs in its own process, owns its data, and communicates via lightweight mechanisms (typically HTTP/REST or messaging).
Microservices vs. Monolith
| Aspect | Monolith | Microservices |
|---|---|---|
| Deployment | Deploy entire app | Deploy services independently |
| Scaling | Scale entire app | Scale specific services |
| Technology | One stack | Each service can use different stack |
| Team Structure | One large team | Small teams own services |
| Failure Scope | One component fails = app fails | One service fails, others continue |
| Complexity | Simpler initially | Complex distributed system |
Key Characteristics
1. Single Responsibility
Each service does ONE thing well.
❌ Monolith: OrderService handles orders, payments, inventory, notifications ✅ Microservices: - OrderService → manages orders - PaymentService → handles payments - InventoryService → tracks stock - NotificationService → sends emails/SMS
2. Independent Deployment
Update and deploy services without touching others.
3. Decentralized Data Management
Each service owns its database. No shared databases.
4. Smart Endpoints, Dumb Pipes
Business logic lives in services, not in the communication layer.
5. Designed for Failure
Services assume other services can fail. Implement retries, fallbacks, circuit breakers.
How Services Communicate
Synchronous (Request/Response)
REST APIs
Order Service → HTTP GET /users/123 → User Service
← { "name": "John", "email": "..." }
gRPC Faster than REST, uses Protocol Buffers. Better for internal service-to-service calls.
Asynchronous (Event-Driven)
Message Queues
Order Service → [order_created event] → Queue → Notification Service
→ Inventory Service
→ Analytics Service
Pros: Services are decoupled, resilient to failures Cons: Eventual consistency, harder to debug
Service Discovery
How do services find each other in a dynamic environment?
Client-Side Discovery
Client queries a registry, then calls the service directly.
Order Service → Registry: "Where is User Service?"
← "http://10.0.0.5:8080"
Order Service → http://10.0.0.5:8080/users/123
Tools: Netflix Eureka, Consul
Server-Side Discovery
Client calls a load balancer, which routes to services.
Order Service → Load Balancer → User Service (instance 1, 2, or 3)
Tools: AWS ALB, Kubernetes Services
API Gateway
A single entry point for all client requests.
Mobile App ─┐
Web App ────┼→ [API Gateway] → User Service
Partner API ┘ → Order Service
→ Payment Service
Responsibilities
- Routing requests to appropriate services
- Authentication/Authorization
- Rate limiting
- Request/response transformation
- Caching
- SSL termination
Tools: Kong, AWS API Gateway, Nginx, Envoy
Data Management Patterns
Database per Service
Each service has its own database. This is the golden rule.
User Service → PostgreSQL (users) Order Service → MongoDB (orders) Product Service → Elasticsearch (products)
Challenge: How to query across services?
Saga Pattern
Manage distributed transactions as a sequence of local transactions.
1. Order Service: Create order (pending) 2. Payment Service: Charge card - Success → continue - Failure → compensate (cancel order) 3. Inventory Service: Reserve stock 4. Order Service: Mark order as confirmed
CQRS (Command Query Responsibility Segregation)
Separate read and write models for complex domains.
Resilience Patterns
Circuit Breaker
Stop calling a failing service to prevent cascade failures.
Normal: Order Service → User Service (works) Failures build up: Order Service → User Service (timeout, timeout, timeout) Circuit OPEN: Order Service → [Circuit Breaker] → Return fallback immediately After cooldown: Order Service → [Circuit Breaker] → Try User Service again
Tools: Netflix Hystrix, Resilience4j, Polly
Retry with Backoff
Retry failed requests with increasing delays.
delays = [100ms, 200ms, 400ms, 800ms, 1600ms] # Exponential backoff
Bulkhead
Isolate service calls so one failing integration doesn't exhaust all threads.
Timeout
Always set timeouts. Never wait forever.
Observability
In microservices, understanding system behavior is hard. You need:
1. Centralized Logging
Aggregate logs from all services. Tools: ELK Stack, Splunk, Datadog
2. Distributed Tracing
Track a request across services. Tools: Jaeger, Zipkin, AWS X-Ray
3. Metrics & Monitoring
Track latency, error rates, throughput. Tools: Prometheus + Grafana, Datadog
4. Alerting
Get notified when things break.
Real-World Examples
Netflix
Hundreds of microservices. Pioneer of many patterns (Eureka, Hystrix, Zuul). Each team owns their services end-to-end.
Uber
Started monolith, migrated to microservices. Services for rides, payments, maps, pricing, notifications. Uses gRPC internally.
Amazon
"Two-pizza teams" each own a service. Services communicate via REST and queues. Led to creation of AWS.
When NOT to Use Microservices
❌ Small team / early-stage startup: Overhead isn't worth it ❌ Simple domain: If a monolith fits, use it ❌ Inexperienced team: Distributed systems are hard ❌ Tightly coupled domains: If everything talks to everything
Start with a modular monolith. Extract services when you have clear team/scaling boundaries.
Migration Strategy: Strangler Fig
Gradually replace parts of a monolith with microservices.
Phase 1: Monolith handles everything Phase 2: New feature as microservice, monolith calls it Phase 3: Extract another piece Phase 4: Monolith is hollowed out, eventually retired
Interview Tips 💡
When discussing microservices in system design:
- Don't default to microservices: "We'd start with a monolith and extract services as the team grows..."
- Justify service boundaries: "We'd have separate services for payments and orders because they have different scaling needs..."
- Discuss communication: "Services would communicate via async events for loose coupling..."
- Address data consistency: "For distributed transactions, we'd use the Saga pattern..."
- Mention observability: "We'd need distributed tracing to debug requests spanning services..."
Related Concepts
- API Gateway Pattern — Entry point for microservices
- Service Discovery — Finding services dynamically
- Message Queues — Async communication between services
- Circuit Breaker — Handling service failures
- Load Balancing — Distributing traffic across service instances
- Distributed Tracing — Observability for microservices
About ScaleWiki
ScaleWiki is an interactive educational platform dedicated to demystifying distributed systems, software architecture, and system design. Our mission is to provide high-quality, technically accurate resources for software engineers preparing for interviews or solving complex scaling challenges in production.
Read more about our Editorial Guidelines & Authorship.
Educational Disclaimer: The architectural patterns and system designs discussed in this article are based on common industry practices, technical whitepapers, and public engineering blogs. Actual implementations in enterprise environments may vary significantly based on specific product requirements, legacy constraints, and evolving technologies.
Related Articles
Caching Strategies
A breakdown of where to place your cache and how to keep it in sync with your database.
CAP Theorem
Consistency, Availability, Partition Tolerance. Why you can only pick two in distributed systems, and how real databases like MongoDB, Cassandra, and DynamoDB make the trade-off.
Circuit Breaker Pattern
A mechanism to prevent an application from repeatedly trying to execute an operation that's likely to fail.