Microservices Architecture: In-Depth Explanation¶
Microservices architecture is a modern approach to software design where applications are broken down into small, independent services that communicate with each other. Unlike monolithic architectures, where everything is tightly coupled, microservices allow flexibility, scalability, and faster deployments.
1. Core Concepts of Microservices¶
a) Decentralization & Independence¶
- Each microservice is independently developed, deployed, and scaled.
- Services communicate via APIs (typically REST, gRPC, or messaging systems like Kafka or RabbitMQ).
- Each microservice owns its data (separate databases per service).
b) Technology Agnostic¶
- Each service can use a different programming language, database, and framework.
- Example: A system could have a user authentication service in Python (Flask), a payments service in Java (Spring Boot), and a recommendation engine in Node.js.
c) Scalability & Resilience¶
- If a service goes down, only that part of the application is affected.
- Services can be scaled independently based on demand.
- Example: A high-traffic service (like authentication) can scale up, while a low-traffic service (like email notifications) remains unchanged.
2. How Docker Fits into Microservices Architecture?¶
a) Containerization of Microservices¶
- Docker packages each microservice with its dependencies into lightweight, portable containers.
- Each microservice runs in its own container, avoiding conflicts with other services.
- Containers ensure consistent behavior across environments (development, testing, production).
Example: Instead of running a Java service with java -jar myapp.jar, we can build a Docker image:
FROM openjdk:17
COPY target/myapp.jar app.jar
CMD ["java", "-jar", "app.jar"]
Then run it in a container:
docker run -d -p 8080:8080 myapp
b) Service Discovery & Networking¶
- Docker provides network isolation for microservices using Docker networks.
- Services communicate over a Docker network instead of hardcoding IP addresses.
- Example: A Node.js backend can connect to a MySQL database using service names like
mysql:3306instead of an IP.
c) Deployment & Scaling¶
- Docker Compose is used for local development to spin up multiple services together.
- Docker Swarm or Kubernetes is used for production-level orchestration (load balancing, scaling, service discovery).
Example (Docker Compose for a 3-Tier App):
version: '3'
services:
backend:
build: ./backend
ports:
- "5000:5000"
networks:
- app-network
frontend:
build: ./frontend
ports:
- "3000:3000"
networks:
- app-network
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: mydb
networks:
- app-network
networks:
app-network:
3. Microservices Communication Patterns¶
a) Synchronous Communication (API Calls)¶
- Services communicate over HTTP/HTTPS using REST or gRPC.
- Example: The User Service makes a request to the Order Service using REST API.
b) Asynchronous Communication (Message Queues)¶
- Services emit events and listen to queues using RabbitMQ, Kafka, or AWS SQS.
- Example: The Order Service publishes an event "Order Created", and the Notification Service listens for this event and sends an email.
4. Data Management in Microservices¶
Each microservice owns its own database to ensure data independence. There are three common patterns:
a) Database-per-Service (Recommended)¶
- Each microservice has its own dedicated database (MySQL, PostgreSQL, MongoDB, etc.).
- Ensures loose coupling but requires careful data consistency management.
b) Shared Database (Not Recommended)¶
- All microservices share a single database schema.
- Easier to implement, but leads to tight coupling and scaling issues.
c) Event Sourcing & CQRS¶
- Command Query Responsibility Segregation (CQRS) separates write and read models.
- Event Sourcing stores all state changes as an event log, allowing rollback and replaying.
5. Deployment Strategies¶
a) Blue-Green Deployment¶
- Two environments: Blue (current) and Green (new version).
- Traffic is switched to the Green environment after successful testing.
b) Canary Deployment¶
- A small percentage of users get the new version before full rollout.
- Used to reduce risk in production deployments.
c) Rolling Updates¶
- Services are updated gradually without downtime.
6. Why Use Kubernetes with Microservices?¶
While Docker manages containers, Kubernetes orchestrates them.
a) Benefits of Kubernetes¶
- Automatic Scaling: Adjusts the number of containers based on traffic.
- Load Balancing: Distributes requests across multiple instances.
- Self-Healing: If a container fails, Kubernetes restarts it.
Example (Kubernetes Deployment for a Microservice):
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: backend:latest
ports:
- containerPort: 5000
Final Thoughts¶
Microservices:¶
- Break a monolith into independent, loosely coupled services.
- Use APIs (REST, gRPC) or message queues (Kafka, RabbitMQ) for communication.
- Each service has its own database for independence.
Docker:¶
- Encapsulates each service in a container with its dependencies.
- Ensures consistent environments across development, testing, and production.
- Uses Docker Compose for local setups and Docker Swarm/Kubernetes for production.
Kubernetes (Advanced):¶
- Manages containerized microservices at scale.
- Provides load balancing, auto-scaling, self-healing features.
Is a 3-Tier Project an Example of Microservices Architecture?¶
Not necessarily. 3-tier architecture and microservices are different concepts, but they can overlap in some cases.
1. 3-Tier Architecture (Traditional Layered Approach)¶
A 3-tier architecture divides an application into three logical layers: - Presentation Layer (Frontend): UI, client-side logic (React, Angular, etc.). - Application Layer (Backend): Business logic, API handling (Node.js, Python, etc.). - Database Layer: Data storage and management (MySQL, PostgreSQL, MongoDB, etc.).
Key Traits: - Each layer has a distinct function. - Typically follows a monolithic approach. - Communication happens vertically between tiers.
2. Microservices Architecture (Service-Oriented Approach)¶
Instead of being separated into layers, a microservices system is split into multiple independent services, each handling a specific business function (e.g., User Service, Order Service, Payment Service).
Key Traits: - Services are independent and loosely coupled. - Each service has its own database (Polyglot Persistence). - Communication happens horizontally between services (via APIs or message queues).
Where Does a 3-Tier Project Fit?¶
It depends on how it is structured: - If each tier is tightly coupled and deployed together β It's a monolithic application with a 3-tier structure. - If tiers are broken down into independent services communicating via APIs β It can be considered a microservices implementation.
Example:
| Architecture | Structure | Communication |
|---|---|---|
| 3-Tier (Monolith) | Backend, frontend, and database are tightly integrated. | Internal function calls between layers. |
| Microservices | Each function (auth, users, orders) is a separate service. | API calls, message queues (Kafka, RabbitMQ). |
Where Does a 2-Tier Project Fall?¶
A 2-tier architecture consists of: - Client (Frontend/Thin Client or Fat Client): UI that directly interacts with the database. - Database (Backend): Stores data, often including business logic (stored procedures).
Key Traits: - The backend and database are tightly coupled. - Used in desktop applications (e.g., MS Access, older enterprise apps). - Less scalable than 3-tier because business logic is inside the database.
Example of a 2-Tier App: - A React app directly accessing a MySQL database via API calls, without a dedicated backend service.
Final Thoughts¶
3-tier is NOT necessarily microservices, but it can be split into microservices by:¶
- Splitting the backend into independent services.
- Giving each service its own database.
- Using API gateways and service discovery (e.g., Kubernetes).
How to Convert a 3-Tier Project into Microservices Architecture¶
We will take your 3-tier application (React, Node.js, MySQL) and transform it into a microservices-based system.
Current 3-Tier Monolithic Architecture¶
Your project currently follows this structure:
π 3TierUserApp
βββ π client (React) β Frontend UI
βββ π server (Node.js) β Backend API & Business Logic
βββ π database (MySQL) β Central Database
Issues with Monolith: - Tightly coupled β A single failure can break the entire system. - Hard to scale β Scaling the backend means scaling the entire app. - Difficult deployments β Any change requires redeploying the entire application.
Transforming into Microservices¶
We'll break this monolithic application into independent services:
Step 1: Identify Microservices
| Service | Function |
|---|---|
| User Service | Handles user authentication & profile management. |
| Frontend Service | Serves the React frontend. |
| Database Service | Manages MySQL storage for all services. |
| API Gateway (Optional) | Routes requests to appropriate services. |
Each microservice will have its own Docker container and communicate via REST APIs.
Step 2: Microservices Architecture Flow Chart¶
Below is the flowchart showing how the system will function in a microservices setup.
+-------------+
| User (UI) |
+-------------+
|
+-------------+
| API Gateway |
+-------------+
|
-------------------------------
| | | |
+----+ +----+ +----+ +----+
|User| |Order| |Auth| |DB |
|Svc | |Svc | |Svc | --> |Svc |
+----+ +----+ +----+ +----+
Explanation of the flowchart: - The User interacts with the frontend (React). - The frontend calls the API Gateway (optional, but improves scalability). - The API Gateway routes requests to the appropriate microservices: - User Service (Manages user data) - Order Service (Manages orders) - Auth Service (Handles authentication) - Each service has its own database (or uses a shared database in the beginning). - Services communicate via REST APIs.
Step 3: Writing Dockerfiles for Each Microservice¶
Each service will have its own Dockerfile.
1. User Service (Node.js)
FROM node:14-alpine
WORKDIR /usr/src/app/user-service
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5001
CMD ["node", "server.js"]
2. Order Service (Node.js)
FROM node:14-alpine
WORKDIR /usr/src/app/order-service
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5002
CMD ["node", "server.js"]
3. Authentication Service
FROM node:14-alpine
WORKDIR /usr/src/app/auth-service
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5003
CMD ["node", "server.js"]
4. Database Service (MySQL)
FROM mysql:latest
ENV MYSQL_ROOT_PASSWORD root
ENV MYSQL_DATABASE userdb
EXPOSE 3306
Step 4: Writing the docker-compose.yml¶
Now, we need to orchestrate all these microservices.
version: '3.8'
services:
user-service:
build: ./user-service
ports:
- "5001:5001"
depends_on:
- db
order-service:
build: ./order-service
ports:
- "5002:5002"
depends_on:
- db
auth-service:
build: ./auth-service
ports:
- "5003:5003"
depends_on:
- db
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: userdb
ports:
- "3306:3306"
Summary: - We converted the 3-tier monolithic structure into microservices. - Each service has its own Dockerfile and runs independently. - We used Docker Compose to manage all services. - Services communicate via APIs instead of internal function calls.
Microservices Project Structure¶
Here is the plaintext tree structure representing the microservices architecture we discussed:
π MicroservicesProject
βββ π user-service
β βββ π Dockerfile
β βββ π package.json
β βββ π server.js
β βββ π controllers
β βββ π models
β βββ π routes
β βββ π config
βββ π order-service
β βββ π Dockerfile
β βββ π package.json
β βββ π server.js
β βββ π controllers
β βββ π models
β βββ π routes
β βββ π config
βββ π auth-service
β βββ π Dockerfile
β βββ π package.json
β βββ π server.js
β βββ π controllers
β βββ π models
β βββ π routes
β βββ π config
βββ π database
β βββ π Dockerfile
β βββ π init.sql
βββ π docker-compose.yml
βββ π README.md
Explanation: - user-service, order-service, and auth-service β Independent microservices. - database β MySQL database setup. - docker-compose.yml β Orchestrates all services.
Microservices Principles in the Repository¶
This repository follows a microservices architecture, evident from its structure. Hereβs how it aligns with the microservices principles:
1. Services Are Independent¶
Each core functionality (ad service, cart service, checkout service, etc.) is separated into different directories under src/. These are likely independent services running in different containers.
2. Containerization & Orchestration¶
- Docker & Kubernetes: The repository includes Dockerfile for each microservice in
src/, and Kubernetes manifests (kubernetes-manifests/,istio-manifests/,helm-chart/). - Helm & Istio: Helm charts (
helm-chart/) and Istio (istio-manifests/) ensure deployment automation and service-to-service communication.
3. Infrastructure as Code (IaC)¶
- Terraform: Found in
.github/terraform/, used for cloud provisioning. - Kustomize: Located in
kustomize/, used for managing Kubernetes configurations. - Cloud Deployment Scripts:
.deploystack/includes scripts and YAML for deployment.
4. CI/CD Pipeline¶
- GitHub Actions workflows are present under
.github/workflows/for continuous integration and testing. skaffold.yamlsuggests the use of Skaffold for Kubernetes-native development.
5. Observability & Monitoring¶
google-cloud-operations/contains OpenTelemetry collector configurations.- Logging and monitoring likely use Google Cloud services.
6. API Communication & Protobuf¶
protos/contains.protofiles, meaning services communicate via gRPC.
This repository is a well-structured microservices project, likely a cloud-native e-commerce or similar application.