πŸ—οΈ Microservices Architecture

Build Scalable, Maintainable Applications

πŸ‘‹ Welcome to Microservices!

Microservices architecture is a modern approach to building applications. Instead of one large application, you build many small, independent services that work together.

Learn how companies like Netflix, Amazon, and Uber build scalable systems!

πŸ€” What are Microservices?

Microservices is an architectural style where an application is composed of small, independent services that communicate over a network. Each service focuses on a specific business capability and can be developed, deployed, and scaled independently.

Simple Analogy:

Monolithic Application (Traditional): Like a single restaurant where one kitchen handles everything - pizza, burgers, sushi, desserts. If the kitchen has a problem, the entire restaurant stops.

Microservices: Like a food court with specialized restaurants - one for pizza, one for burgers, one for sushi. If the pizza place has issues, the others keep working!

βš–οΈ Monolithic vs Microservices

Aspect Monolithic Microservices
Structure Single codebase Multiple independent services
Deployment Deploy entire application Deploy services independently
Scaling Scale entire application Scale individual services
Technology Single tech stack Different tech per service
Development One team, one codebase Multiple teams, multiple codebases
Failure Impact Entire app goes down Only affected service fails
Complexity Simple to start Complex infrastructure

🎯 Key Principles

🎯

Single Responsibility

Each service does one thing well

Focus on specific business capability

πŸ”’

Autonomy

Services are independent

Own database, own deployment

πŸ”—

Decentralization

No central control

Services make own decisions

πŸ›‘οΈ

Resilience

Failure isolation

Graceful degradation

πŸ—οΈ Microservices Architecture Example

E-Commerce Application

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ API Gateway β”‚ β”‚ (Entry point for all requests) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Service β”‚ β”‚Product Svc β”‚ β”‚ Order Service β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Register β”‚ β”‚ - Catalog β”‚ β”‚ - Create Order β”‚ β”‚ - Login β”‚ β”‚ - Search β”‚ β”‚ - Track Order β”‚ β”‚ - Profile β”‚ β”‚ - Inventory β”‚ β”‚ - History β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User DB β”‚ β”‚ Product DB β”‚ β”‚ Order DB β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Payment Service β”‚ β”‚ Notification Svc β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Process Pay β”‚ β”‚ - Email β”‚ β”‚ - Refunds β”‚ β”‚ - SMS β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”§ Building Microservices

User Service Example (Node.js/Express)

// user-service/server.js const express = require('express'); const app = express(); app.use(express.json()); // In-memory database (use real DB in production) let users = []; // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'user-service' }); }); // Register user app.post('/api/users/register', (req, res) => { const { name, email, password } = req.body; // Check if user exists if (users.find(u => u.email === email)) { return res.status(400).json({ error: 'User already exists' }); } const newUser = { id: users.length + 1, name, email, password, // Hash in production! createdAt: new Date() }; users.push(newUser); res.status(201).json({ id: newUser.id, name, email }); }); // Get user by ID app.get('/api/users/:id', (req, res) => { const user = users.find(u => u.id === parseInt(req.params.id)); if (!user) { return res.status(404).json({ error: 'User not found' }); } // Don't send password const { password, ...userWithoutPassword } = user; res.json(userWithoutPassword); }); // Login app.post('/api/users/login', (req, res) => { const { email, password } = req.body; const user = users.find(u => u.email === email && u.password === password); if (!user) { return res.status(401).json({ error: 'Invalid credentials' }); } res.json({ message: 'Login successful', userId: user.id }); }); const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`User Service running on port ${PORT}`); });

Product Service Example

// product-service/server.js const express = require('express'); const app = express(); app.use(express.json()); let products = [ { id: 1, name: 'Laptop', price: 999, stock: 10 }, { id: 2, name: 'Phone', price: 699, stock: 25 } ]; // Health check app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'product-service' }); }); // Get all products app.get('/api/products', (req, res) => { res.json(products); }); // Get product by ID app.get('/api/products/:id', (req, res) => { const product = products.find(p => p.id === parseInt(req.params.id)); if (!product) { return res.status(404).json({ error: 'Product not found' }); } res.json(product); }); // Create product app.post('/api/products', (req, res) => { const { name, price, stock } = req.body; const newProduct = { id: products.length + 1, name, price, stock }; products.push(newProduct); res.status(201).json(newProduct); }); // Update stock (called by order service) app.patch('/api/products/:id/stock', (req, res) => { const product = products.find(p => p.id === parseInt(req.params.id)); if (!product) { return res.status(404).json({ error: 'Product not found' }); } const { quantity } = req.body; if (product.stock < quantity) { return res.status(400).json({ error: 'Insufficient stock' }); } product.stock -= quantity; res.json(product); }); const PORT = process.env.PORT || 3002; app.listen(PORT, () => { console.log(`Product Service running on port ${PORT}`); });

Order Service (Communicates with other services)

// order-service/server.js const express = require('express'); const axios = require('axios'); const app = express(); app.use(express.json()); let orders = []; const USER_SERVICE = 'http://localhost:3001'; const PRODUCT_SERVICE = 'http://localhost:3002'; // Health check app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'order-service' }); }); // Create order app.post('/api/orders', async (req, res) => { try { const { userId, productId, quantity } = req.body; // 1. Verify user exists const userResponse = await axios.get(`${USER_SERVICE}/api/users/${userId}`); const user = userResponse.data; // 2. Get product details const productResponse = await axios.get(`${PRODUCT_SERVICE}/api/products/${productId}`); const product = productResponse.data; // 3. Check stock and update await axios.patch(`${PRODUCT_SERVICE}/api/products/${productId}/stock`, { quantity }); // 4. Create order const newOrder = { id: orders.length + 1, userId, productId, quantity, totalPrice: product.price * quantity, status: 'pending', createdAt: new Date() }; orders.push(newOrder); res.status(201).json(newOrder); } catch (error) { console.error('Order creation failed:', error.message); res.status(500).json({ error: 'Failed to create order', details: error.response?.data || error.message }); } }); // Get user orders app.get('/api/orders/user/:userId', (req, res) => { const userOrders = orders.filter(o => o.userId === parseInt(req.params.userId)); res.json(userOrders); }); // Get order by ID app.get('/api/orders/:id', (req, res) => { const order = orders.find(o => o.id === parseInt(req.params.id)); if (!order) { return res.status(404).json({ error: 'Order not found' }); } res.json(order); }); const PORT = process.env.PORT || 3003; app.listen(PORT, () => { console.log(`Order Service running on port ${PORT}`); });

πŸšͺ API Gateway

What is an API Gateway?

An API Gateway is the single entry point for all client requests. It routes requests to appropriate microservices, handles authentication, rate limiting, and more.

Simple API Gateway Example

// api-gateway/server.js const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); // Route requests to appropriate services app.use('/api/users', createProxyMiddleware({ target: 'http://localhost:3001', changeOrigin: true })); app.use('/api/products', createProxyMiddleware({ target: 'http://localhost:3002', changeOrigin: true })); app.use('/api/orders', createProxyMiddleware({ target: 'http://localhost:3003', changeOrigin: true })); // Health check for all services app.get('/health', async (req, res) => { const services = [ { name: 'user-service', url: 'http://localhost:3001/health' }, { name: 'product-service', url: 'http://localhost:3002/health' }, { name: 'order-service', url: 'http://localhost:3003/health' } ]; const healthChecks = await Promise.all( services.map(async (service) => { try { const response = await axios.get(service.url); return { ...service, status: 'healthy' }; } catch (error) { return { ...service, status: 'unhealthy' }; } }) ); res.json({ gateway: 'healthy', services: healthChecks }); }); const PORT = 3000; app.listen(PORT, () => { console.log(`API Gateway running on port ${PORT}`); });

πŸ“‘ Service Communication

Synchronous (REST/HTTP)

Direct communication

  • Service A calls Service B
  • Waits for response
  • Simple but creates coupling

Asynchronous (Message Queue)

Event-driven communication

  • Services publish events
  • Other services subscribe
  • Loose coupling

Message Queue Example (RabbitMQ)

// Install: npm install amqplib // Publisher (Order Service) const amqp = require('amqplib'); async function publishOrderCreated(orderData) { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); const exchange = 'orders'; await channel.assertExchange(exchange, 'fanout', { durable: false }); const message = JSON.stringify(orderData); channel.publish(exchange, '', Buffer.from(message)); console.log('Order created event published:', orderData); setTimeout(() => { connection.close(); }, 500); } // Subscriber (Notification Service) async function subscribeToOrders() { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); const exchange = 'orders'; await channel.assertExchange(exchange, 'fanout', { durable: false }); const q = await channel.assertQueue('', { exclusive: true }); channel.bindQueue(q.queue, exchange, ''); console.log('Waiting for order events...'); channel.consume(q.queue, (msg) => { const order = JSON.parse(msg.content.toString()); console.log('Received order:', order); // Send notification sendEmailNotification(order); }, { noAck: true }); }

🐳 Docker & Containerization

Why Docker for Microservices?

Dockerfile Example

# user-service/Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install COPY . . EXPOSE 3001 CMD ["node", "server.js"]

Docker Compose (Run all services)

# docker-compose.yml version: '3.8' services: user-service: build: ./user-service ports: - "3001:3001" environment: - PORT=3001 - DB_HOST=user-db depends_on: - user-db product-service: build: ./product-service ports: - "3002:3002" environment: - PORT=3002 - DB_HOST=product-db depends_on: - product-db order-service: build: ./order-service ports: - "3003:3003" environment: - PORT=3003 - USER_SERVICE_URL=http://user-service:3001 - PRODUCT_SERVICE_URL=http://product-service:3002 api-gateway: build: ./api-gateway ports: - "3000:3000" depends_on: - user-service - product-service - order-service user-db: image: postgres:15 environment: POSTGRES_DB: users POSTGRES_PASSWORD: password product-db: image: postgres:15 environment: POSTGRES_DB: products POSTGRES_PASSWORD: password # Run all services: docker-compose up

πŸ’‘ Best Practices

Microservices Best Practices:

⚠️ Challenges

Common Challenges:

Solution: Use proper tools (Kubernetes, service mesh, monitoring tools)

πŸ› οΈ Essential Tools

Kubernetes

Container orchestration

  • Deploy & scale services
  • Load balancing
  • Self-healing

Docker

Containerization platform

  • Package services
  • Consistent environments
  • Easy deployment

RabbitMQ/Kafka

Message brokers

  • Async communication
  • Event streaming
  • Decoupling services

Prometheus/Grafana

Monitoring & visualization

  • Metrics collection
  • Alerting
  • Dashboards

πŸŽ“ Our Training Course

Learn Microservices

Take our comprehensive Microservices course:

πŸ“š Microservices Course β†’

πŸš€ Master Microservices!

Build scalable, resilient applications

Start Learning β†’

πŸ“– Related Topics