实战:微服务架构
嘿!长安来教你用Docker构建微服务架构!这是真正的企业级应用!🚀
🎯 项目概述
我们要构建一个电商系统的微服务架构,包括:
- API Gateway:统一入口
- User Service:用户服务
- Product Service:商品服务
- Order Service:订单服务
- MySQL:关系型数据库
- MongoDB:文档数据库
- Redis:缓存
- RabbitMQ:消息队列
这就是真实的微服务架构! 🎉
📁 项目结构
microservices-ecommerce/
├── services/
│ ├── api-gateway/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── src/
│ ├── user-service/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── src/
│ ├── product-service/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── src/
│ └── order-service/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
├── docker-compose.yml
├── .env.example
└── README.md
🔧 服务实现
1. API Gateway(API网关)
services/api-gateway/Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
USER node
EXPOSE 3000
CMD ["node", "src/index.js"]
services/api-gateway/src/index.js:
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3000;
// 服务地址
const SERVICES = {
user: process.env.USER_SERVICE_URL || 'http://user-service:3001',
product: process.env.PRODUCT_SERVICE_URL || 'http://product-service:3002',
order: process.env.ORDER_SERVICE_URL || 'http://order-service:3003'
};
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'api-gateway' });
});
// 路由转发
app.all('/users/*', async (req, res) => {
try {
const url = req.url.replace('/users', '');
const response = await axios({
method: req.method,
url: `${SERVICES.user}${url}`,
data: req.body
});
res.json(response.data);
} catch (error) {
res.status(error.response?.status || 500).json({
error: error.message
});
}
});
app.all('/products/*', async (req, res) => {
try {
const url = req.url.replace('/products', '');
const response = await axios({
method: req.method,
url: `${SERVICES.product}${url}`,
data: req.body
});
res.json(response.data);
} catch (error) {
res.status(error.response?.status || 500).json({
error: error.message
});
}
});
app.all('/orders/*', async (req, res) => {
try {
const url = req.url.replace('/orders', '');
const response = await axios({
method: req.method,
url: `${SERVICES.order}${url}`,
data: req.body
});
res.json(response.data);
} catch (error) {
res.status(error.response?.status || 500).json({
error: error.message
});
}
});
app.listen(PORT, () => {
console.log(`🚪 API Gateway 运行在 ${PORT}`);
});
2. User Service(用户服务)
services/user-service/src/index.js:
const express = require('express');
const mysql = require('mysql2/promise');
const redis = require('redis');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3001;
// MySQL连接池
const pool = mysql.createPool({
host: process.env.DB_HOST || 'mysql',
user: process.env.DB_USER || 'user',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_NAME || 'users_db',
waitForConnections: true,
connectionLimit: 10
});
// Redis客户端
const redisClient = redis.createClient({
url: process.env.REDIS_URL || 'redis://redis:6379'
});
redisClient.connect();
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'user-service' });
});
// 获取所有用户
app.get('/', async (req, res) => {
try {
// 尝试从缓存获取
const cached = await redisClient.get('users:all');
if (cached) {
return res.json({
source: 'cache',
users: JSON.parse(cached)
});
}
// 从数据库查询
const [rows] = await pool.query('SELECT * FROM users');
// 存入缓存
await redisClient.setEx('users:all', 60, JSON.stringify(rows));
res.json({ source: 'database', users: rows });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 创建用户
app.post('/', async (req, res) => {
try {
const { name, email } = req.body;
const [result] = await pool.query(
'INSERT INTO users (name, email) VALUES (?, ?)',
[name, email]
);
// 清除缓存
await redisClient.del('users:all');
res.status(201).json({
id: result.insertId,
name,
email
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`👥 User Service 运行在 ${PORT}`);
});
3. Product Service(商品服务)
services/product-service/src/index.js:
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3002;
// MongoDB连接
mongoose.connect(process.env.MONGO_URI || 'mongodb://mongo:27017/products_db');
// 商品模型
const Product = mongoose.model('Product', {
name: String,
description: String,
price: Number,
stock: Number,
createdAt: { type: Date, default: Date.now }
});
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'product-service' });
});
// 获取所有商品
app.get('/', async (req, res) => {
try {
const products = await Product.find();
res.json({ products });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 创建商品
app.post('/', async (req, res) => {
try {
const product = new Product(req.body);
await product.save();
res.status(201).json({ product });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 获取单个商品
app.get('/:id', async (req, res) => {
try {
const product = await Product.findById(req.params.id);
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
res.json({ product });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`📦 Product Service 运行在 ${PORT}`);
});
4. Order Service(订单服务)
services/order-service/src/index.js:
const express = require('express');
const mongoose = require('mongoose');
const amqp = require('amqplib');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3003;
// MongoDB连接
mongoose.connect(process.env.MONGO_URI || 'mongodb://mongo:27017/orders_db');
// 订单模型
const Order = mongoose.model('Order', {
userId: Number,
productId: String,
quantity: Number,
totalPrice: Number,
status: { type: String, default: 'pending' },
createdAt: { type: Date, default: Date.now }
});
// RabbitMQ连接
let channel;
async function connectRabbitMQ() {
try {
const connection = await amqp.connect(
process.env.RABBITMQ_URL || 'amqp://rabbitmq:5672'
);
channel = await connection.createChannel();
await channel.assertQueue('orders');
console.log('✅ RabbitMQ连接成功');
} catch (error) {
console.error('❌ RabbitMQ连接失败:', error);
setTimeout(connectRabbitMQ, 5000);
}
}
connectRabbitMQ();
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'order-service' });
});
// 创建订单
app.post('/', async (req, res) => {
try {
const order = new Order(req.body);
await order.save();
// 发送消息到队列
if (channel) {
channel.sendToQueue('orders', Buffer.from(JSON.stringify(order)));
}
res.status(201).json({ order });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 获取所有订单
app.get('/', async (req, res) => {
try {
const orders = await Order.find();
res.json({ orders });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`🛒 Order Service 运行在 ${PORT}`);
});
🎨 Docker Compose配置
docker-compose.yml:
version: '3.8'
services:
# API Gateway
api-gateway:
build: ./services/api-gateway
container_name: ecommerce-gateway
ports:
- "3000:3000"
environment:
USER_SERVICE_URL: http://user-service:3001
PRODUCT_SERVICE_URL: http://product-service:3002
ORDER_SERVICE_URL: http://order-service:3003
depends_on:
- user-service
- product-service
- order-service
networks:
- frontend
restart: unless-stopped
# User Service
user-service:
build: ./services/user-service
container_name: ecommerce-user
environment:
DB_HOST: mysql
DB_USER: user
DB_PASSWORD: password
DB_NAME: users_db
REDIS_URL: redis://redis:6379
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
restart: unless-stopped
# Product Service
product-service:
build: ./services/product-service
container_name: ecommerce-product
environment:
MONGO_URI: mongodb://mongo:27017/products_db
depends_on:
mongo:
condition: service_healthy
networks:
- frontend
- backend
restart: unless-stopped
# Order Service
order-service:
build: ./services/order-service
container_name: ecommerce-order
environment:
MONGO_URI: mongodb://mongo:27017/orders_db
RABBITMQ_URL: amqp://rabbitmq:5672
depends_on:
mongo:
condition: service_healthy
rabbitmq:
condition: service_healthy
networks:
- frontend
- backend
restart: unless-stopped
# MySQL(用户服务数据库)
mysql:
image: mysql:8.0
container_name: ecommerce-mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: users_db
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- mysql-data:/var/lib/mysql
- ./init/mysql:/docker-entrypoint-initdb.d
networks:
- backend
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# MongoDB(商品和订单服务)
mongo:
image: mongo:6
container_name: ecommerce-mongo
volumes:
- mongo-data:/data/db
networks:
- backend
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# Redis(缓存)
redis:
image: redis:7-alpine
container_name: ecommerce-redis
volumes:
- redis-data:/data
networks:
- backend
restart: unless-stopped
# RabbitMQ(消息队列)
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: ecommerce-rabbitmq
ports:
- "15672:15672" # 管理界面
volumes:
- rabbitmq-data:/var/lib/rabbitmq
networks:
- backend
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes:
mysql-data:
mongo-data:
redis-data:
rabbitmq-data:
🚀 启动和测试
启动所有服务
# 构建并启动
docker-compose up --build -d
# 查看状态
docker-compose ps
# 查看日志
docker-compose logs -f
测试API
# 1. 健康检查
curl http://localhost:3000/health
# 2. 创建用户
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{
"name": "长安",
"email": "changan@example.com"
}'
# 3. 获取用户列表
curl http://localhost:3000/users
# 4. 创建商品
curl -X POST http://localhost:3000/products \
-H "Content-Type: application/json" \
-d '{
"name": "Docker教程",
"description": "长安的Docker教程",
"price": 99,
"stock": 100
}'
# 5. 获取商品列表
curl http://localhost:3000/products
# 6. 创建订单
curl -X POST http://localhost:3000/orders \
-H "Content-Type: application/json" \
-d '{
"userId": 1,
"productId": "商品ID",
"quantity": 2,
"totalPrice": 198
}'
# 7. 获取订单列表
curl http://localhost:3000/orders
访问管理界面
- RabbitMQ管理界面:http://localhost:15672
用户名:guest
密码:guest
📊 监控和调试
查看服务日志
# 所有服务
docker-compose logs -f
# 特定服务
docker-compose logs -f api-gateway
docker-compose logs -f user-service
查看资源使用
docker stats
进入容器调试
# 进入API Gateway
docker exec -it ecommerce-gateway sh
# 进入MySQL
docker exec -it ecommerce-mysql mysql -uuser -ppassword
# 进入MongoDB
docker exec -it ecommerce-mongo mongosh
# 进入Redis
docker exec -it ecommerce-redis redis-cli
💡 微服务架构优势
1. 独立部署
# 只更新用户服务
docker-compose up -d --no-deps --build user-service
2. 技术栈自由
- User Service:MySQL + Redis
- Product Service:MongoDB
- Order Service:MongoDB + RabbitMQ
3. 横向扩展
# 扩容商品服务到3个实例
docker-compose up -d --scale product-service=3
4. 故障隔离
一个服务挂了,不影响其他服务。
🎯 生产环境优化
1. 添加负载均衡(Nginx)
services:
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
depends_on:
- api-gateway
2. 添加服务发现(Consul)
services:
consul:
image: consul:latest
ports:
- "8500:8500"
3. 添加监控(Prometheus + Grafana)
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3001:3000"
💡 小结
今天长安带你构建了一个完整的微服务架构:
完成的功能
✅ API Gateway(统一入口)
✅ 3个微服务(用户、商品、订单)
✅ 多数据库(MySQL、MongoDB、Redis)
✅ 消息队列(RabbitMQ)
✅ 服务隔离和通信
学到的技能
- 微服务架构设计
- 服务间通信
- 数据库选型
- 消息队列使用
- Docker多容器编排
🚀 下一步
实战项目都完成了!遇到问题怎么办?看 常见问题!
💬 长安的微服务心得:
微服务不是银弹,别为了微服务而微服务!
什么时候用微服务?
- 团队大(10人+)
- 项目复杂
- 需要独立部署
- 需要技术栈多样性
小项目别用微服务!
- 团队小(5人以下)
- 项目简单
- 单体架构就够了
记住:简单是美德,复杂是负担!
但学习微服务还是很有必要的,这是未来趋势!💪
