Module 7: Microservices Architecture
Design and implement scalable microservices-based systems.
What are Microservices?
Microservices is an architectural style where an application is built as a collection of small, independent services. Think of it like a restaurant with specialized stations (pizza, salads, desserts) instead of one chef doing everything.
🎯 Microservices Benefits:
- Independent Deployment: Deploy services separately
- Technology Diversity: Use different tech per service
- Scalability: Scale services independently
- Fault Isolation: One service failure doesn't crash all
- Team Autonomy: Teams own specific services
- Easier Maintenance: Smaller, focused codebases
Monolith vs Microservices
Monolithic
- ✅ Simple to develop initially
- ✅ Easy to test and deploy
- ✅ Better performance (no network calls)
- ❌ Hard to scale specific features
- ❌ Long deployment times
- ❌ Technology lock-in
Microservices
- ✅ Independent scaling
- ✅ Technology flexibility
- ✅ Faster deployments
- ❌ Complex infrastructure
- ❌ Network latency
- ❌ Distributed system challenges
Service Communication
1. REST APIs (Synchronous)
Services communicate via HTTP REST calls.
// User Service calls Order Service
const axios = require('axios');
const orders = await axios.get(
'http://order-service:3001/orders',
{ params: { userId: user.id } }
);
2. Message Queues (Asynchronous)
Services communicate via message brokers (RabbitMQ, Kafka).
// Publisher (Order Service)
const amqp = require('amqplib');
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
await channel.assertQueue('order.created');
channel.sendToQueue('order.created', Buffer.from(
JSON.stringify({ orderId: 123, userId: 456 })
));
// Consumer (Email Service)
channel.consume('order.created', (msg) => {
const order = JSON.parse(msg.content.toString());
sendOrderConfirmationEmail(order);
channel.ack(msg);
});
3. gRPC (High Performance)
Binary protocol for fast service-to-service communication.
// user.proto
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
int32 id = 1;
string name = 2;
string email = 3;
}
Service Discovery & Load Balancing
Consul Service Discovery:
const Consul = require('consul');
const consul = new Consul();
// Register service
await consul.agent.service.register({
name: 'user-service',
address: 'localhost',
port: 3000,
check: {
http: 'http://localhost:3000/health',
interval: '10s'
}
});
// Discover service
const services = await consul.health.service('user-service');
const service = services[0];
const url = `http://${service.Service.Address}:${service.Service.Port} `;
API Gateway Pattern
Single entry point for all client requests. Routes to appropriate microservices.
Express Gateway Example:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// Route to User Service
app.use('/api/users', createProxyMiddleware({
target: 'http://user-service:3000',
changeOrigin: true
}));
// Route to Order Service
app.use('/api/orders', createProxyMiddleware({
target: 'http://order-service:3001',
changeOrigin: true
}));
app.listen(8080);
Microservices Best Practices
1. Database per Service
Each service owns its database. No shared databases.
2. Circuit Breaker Pattern
Prevent cascading failures when a service is down.
3. Distributed Tracing
Track requests across services (Jaeger, Zipkin).
4. Centralized Logging
Aggregate logs from all services (ELK Stack).
5. Health Checks
Each service exposes /health endpoint.
6. Containerization
Use Docker and Kubernetes for deployment.
📚 Module Summary
You've mastered microservices architecture:
- ✓ Microservices vs monolithic architecture
- ✓ Service communication patterns (REST, message queues, gRPC)
- ✓ Service discovery and load balancing
- ✓ API Gateway pattern
- ✓ Best practices and patterns
Congratulations! You've completed the Backend & APIs path! 🎉