🧩 微服务架构
📖 定义
微服务架构(MSA, Microservices Architecture)是一种架构模式,将一个大型应用程序拆分为多个小型、独立的服务进行开发和部署。每个服务负责特定的业务功能,可以独立部署和扩展。与单体(Monolithic)架构不同,它通 过服务间的松耦合提供灵活性和可扩展性。
🎯 通过类比理解
大型企业 vs 初创公司联盟
单体架构 = 大型企业
├─ 所有部门在一栋楼里
├─ 集中管理
├─ 一个部门出问题 → 影响全公司
├─ 难以改变
└─ 决策缓慢
微服务 = 初创公司联盟
├─ 每个团队有独立办公室
├─ 自主决策
├─ 一个团队出问题 → 其他团队正常运作
├─ 快速变更
└─ 灵活扩展
乐高 vs 粘土
单体架构 = 粘土块
┌──────────────────────────────┐
│ 用户 │ 商品 │ 订单 │
│ 管理 │ 管理 │ 管理 │
│ 全部在一起 │
└──────────────────────────────┘
- 必须重做整个东西
- 修改一部分 → 影响整体
- 难以扩展
微服务 = 乐高积木
┌─────┐ ┌─────┐ ┌─────┐
│用户 │ │商品│ │订单│
│服务│ │服务│ │服务│
└─────┘ └─────┘ └─────┘
- 容易替换积木
- 独立修改
- 只扩展需要的部分
⚙️ 工作原理
1. 单体架构 vs 微服务
========== 单体架构 ==========
┌─────────────────────────────────────┐
│ 单个应用程序 │
│ │
│ ┌─────────────────────────────┐ │
│ │ 用户管理模块 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 商品管理模块 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 订单管理模块 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 支付模块 │ │
│ └─────────────────────────────┘ │
│ │
│ 单个数据库 │
│ 单个代码库 │
│ 单个部署单元 │
└─────────────────────────────────────┘
优点:
✅ 初期开发快
✅ 测试简单
✅ 部署简单(只有一个)
✅ 调试容易
缺点:
❌ 规模扩大后复杂
❌ 部署时整体停机
❌ 无法部分扩展
❌ 难以更改技术栈
========== 微服务 ==========
┌──────────┐ ┌──────────┐ ┌──────────┐
│用户 │ │商品 │ │订单 │
│服务 │ │服务 │ │服务 │
│ │ │ │ │ │
│Node.js │ │Java │ │Go │
│MongoDB │ │MySQL │ │PostgreSQL│
└──────────┘ └──────────┘ └──────────┘
↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│支付 │ │通知 │ │评论 │
│服务 │ │服务 │ │服务 │
│ │ │ │ │ │
│Python │ │Node.js │ │Ruby │
│Redis │ │Kafka │ │Cassandra │
└──────────┘ └──────────┘ └──────────┘
优点:
✅ 独立部署
✅ 技术栈自由
✅ 可部分扩展
✅ 团队独立
✅ 故障隔离
缺点:
❌ 初期复杂度高
❌ 网络通信开销
❌ 分布式事务困难
❌ 测试复杂
❌ 运维成本增加
2. 服务间通信
========== 同步通信 (HTTP/REST) ==========
订单服务 → 商品服务
"商品123有库存吗?"
↓
"有,还有5个"
↓
订单服务 → 支付服务
"请处理10,000元支付"
↓
"支付完成"
↓
订单完成
优点: 简单、直观
缺点: 一个服务故障时整体失败
========== 异步通信 (消息队列) ==========
订单服务 → 消息队列
发布"订单已创建"消息
↓
┌──────────────────┐
│ Message Queue │
│ (RabbitMQ, │
│ Kafka 等) │
└──────────────────┘
↓
┌────┴────┬────────┐
↓ ↓ ↓
支付 通知 库存
服务 服务 服务
各自独立处理
优点: 松耦合、故障隔离
缺点: 复杂度增加、调试困难
========== API Gateway ==========
客户端 (移动/Web)
↓
┌──────────────────┐
│ API Gateway │
│ - 路由 │
│ - 认证 │
│ - 负载均衡 │
│ - 日志 │
└──────────────────┘
┌────┴────┬────────┐
↓ ↓ ↓
服务A 服务B 服务C
作用:
- 单一入口点
- 简化客户端
- 处理通用功能
3. 数据管理
========== 单体架构: 共享数据库 ==========
┌─────────────────────────────────────┐
│ 应用程序 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │模块A│ │模块B│ │模块C│ │
│ └──┬──┘ └──┬──┘ └──┬──┘ │
└─────┼────────┼───────┼──────────────┘
└────────┼───────┘
↓
┌──────────────────┐
│ 单个数据库 │
│ ┌────┬────┬────┐│
│ │TA│TB│TC││
│ └────┴────┴────┘│
└──────────────────┘
优点: JOIN容易、保证一致性
缺点: 耦合度高、难以扩展
========== 微服务: 每个服务一个数据库 ==========
┌──────────┐ ┌──────────┐ ┌──────────┐
│服务 A │ │服务 B │ │服务 C │
└────┬─────┘ └─── ─┬─────┘ └────┬─────┘
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│ DB A │ │ DB B │ │ DB C │
│ (MySQL) │ │(MongoDB)│ │(PostgreSQL)│
└─────────┘ └─────────┘ └─────────┘
优点: 独立性、技术选择自由
缺点: 无法JOIN、一致性困难
========== 数据一致性 ==========
// Saga 模式
1. 订单服务: 创建订单
2. 支付服务: 处理支付
3. 库存服务: 减少库存
4. 配送服务: 开始配送
如果第3步失败?
→ 补偿事务 (Compensating Transaction)
4. 库存减少失败
3. 取消支付 ← 补偿
2. 取消订单 ← 补偿
💡 实际示例
单体架构示例 (Express.js)
// ========== 单体应用程序 ==========
// server.js - 所有功 能在一个文件中
const express = require('express');
const app = express();
app.use(express.json());
// 单个数据库
const db = require('./database');
// ========== 用户管理 ==========
app.post('/api/users', async (req, res) => {
const { username, email, password } = req.body;
const user = await db.users.create({ username, email, password });
res.json(user);
});
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user);
});
// ========== 商品管理 ==========
app.post('/api/products', async (req, res) => {
const { name, price, stock } = req.body;
const product = await db.products.create({ name, price, stock });
res.json(product);
});
app.get('/api/products', async (req, res) => {
const products = await db.products.findAll();
res.json(products);
});
// ========== 订单管理 ==========
app.post('/api/orders', async (req, res) => {
const { userId, productId, quantity } = req.body;
// 事务保证一致性
const transaction = await db.sequelize.transaction();
try {
// 1. 检查库存
const product = await db.products.findById(productId, { transaction });
if (product.stock < quantity) {
throw new Error('库存不足');
}
// 2. 减少库存
await product.update(
{ stock: product.stock - quantity },
{ transaction }
);
// 3. 创建订单
const order = await db.orders.create(
{ userId, productId, quantity, total: product.price * quantity },
{ transaction }
);
// 4. 处理支付
await processPayment(order.total);
await transaction.commit();
res.json(order);
} catch (error) {
await transaction.rollback();
res.status(400).json({ error: error.message });
}
});
// ========== 支付处理 ==========
app.post('/api/payments', async (req, res) => {
const { orderId, amount } = req.body;
const payment = await db.payments.create({ orderId, amount });
res.json(payment);
});
// 作为单个服务器运行
app.listen(3000, () => {
console.log('单体服务器运行中: http://localhost:3000');
});
/*
优点:
- 代码在一处
- 开发快
- 调试简单
- 事务简单
缺点:
- 规模扩大后复杂
- 部署时整体重启
- 无法部分扩展
- 一个功能故障 → 影响整体
*/
微服务示例
// ========== 1. 用户服务 (user-service.js) ==========
// 端口: 3001
const express = require('express');
const app = express();
const mongoose = require('mongoose');
app.use(express.json());
// 独立数据库
mongoose.connect('mongodb://localhost/users-db');
const User = mongoose.model('User', {
username: String,
email: String,
password: String
});
// 创建用户
app.post('/users', async (req, res) => {
const { username, email, password } = req.body;
try {
const user = new User({ username, email, password });
await user.save();
// 发布事件(通知其他服务)
await publishEvent('user.created', { userId: user._id, email });
res.json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// 获取用户
app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
});
app.listen(3001, () => {
console.log('用户服务: http://localhost:3001');
});
// ========== 2. 商品服务 (product-service.js) ==========
// 端口: 3002
const express = require('express');
const app = express();
const { Pool } = require('pg');
app.use(express.json());
// 使用 PostgreSQL (不同的数据库!)
const pool = new Pool({
host: 'localhost',
database: 'products-db',
port: 5432
});
// 商品列表
app.get('/products', async (req, res) => {
const result = await pool.query('SELECT * FROM products');
res.json(result.rows);
});
// 商品详情
app.get('/products/:id', async (req, res) => {
const result = await pool.query(
'SELECT * FROM products WHERE id = $1',
[req.params.id]
);
res.json(result.rows[0]);
});
// 检查库存
app.get('/products/:id/stock', async (req, res) => {
const result = await pool.query(
'SELECT stock FROM products WHERE id = $1',
[req.params.id]
);
res.json({ stock: result.rows[0].stock });
});
// 减少库存
app.post('/products/:id/decrease-stock', async (req, res) => {
const { quantity } = req.body;
const client = await pool.connect();
try {
await client.query('BEGIN');
// 检查当前库存
const result = await client.query(
'SELECT stock FROM products WHERE id = $1 FOR UPDATE',
[req.params.id]
);
const currentStock = result.rows[0].stock;
if (currentStock < quantity) {
throw new Error('库存不足');
}
// 减少库存
await client.query(
'UPDATE products SET stock = stock - $1 WHERE id = $2',
[quantity, req.params.id]
);
await client.query('COMMIT');
res.json({ success: true });
} catch (error) {
await client.query('ROLLBACK');
res.status(400).json({ error: error.message });
} finally {
client.release();
}
});
app.listen(3002, () => {
console.log('商品服务: http://localhost:3002');
});
// ========== 3. 订单服务 (order-service.js) ==========
// 端口: 3003
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const orders = []; // 实际使用数据库
// 创建订单
app.post('/orders', async (req, res) => {
const { userId, productId, quantity } = req.body;
try {
// 1. 检查用户(调用用户服务)
const userResponse = await axios.get(
`http://localhost:3001/users/${userId}`
);
const user = userResponse.data;
if (!user) {
return res.status(404).json({ error: '未找到用户' });
}
// 2. 获取商品信息(调用商品服务)
const productResponse = await axios.get(
`http://localhost:3002/products/${productId}`
);
const product = productResponse.data;
// 3. 检查库存
const stockResponse = await axios.get(
`http://localhost:3002/products/${productId}/stock`
);
const { stock } = stockResponse.data;
if (stock < quantity) {
return res.status(400).json({ error: '库存不足' });
}
// 4. 减少库存
await axios.post(
`http://localhost:3002/products/${productId}/decrease-stock`,
{ quantity }
);
// 5. 处理支付(调用支付服务)
const total = product.price * quantity;
const paymentResponse = await axios.post(
'http://localhost:3004/payments',
{ userId, amount: total }
);
// 6. 创建订单
const order = {
id: orders.length + 1,
userId,
productId,
quantity,
total,
status: 'completed',
createdAt: new Date()
};
orders.push(order);
// 7. 发布事件
await publishEvent('order.created', order);
res.json(order);
} catch (error) {
// Saga 模式: 补偿事务
console.error('订单失败:', error.message);
// 恢复库存
try {
await axios.post(
`http://localhost:3002/products/${productId}/increase-stock`,
{ quantity }
);
} catch (rollbackError) {
console.error('恢复库存失败:', rollbackError.message);
}
res.status(500).json({ error: '订单处理失败' });
}
});
// 获取订单
app.get('/orders/:id', (req, res) => {
const order = orders.find(o => o.id === parseInt(req.params.id));
res.json(order);
});
app.listen(3003, () => {
console.log('订单服务: http://localhost:3003');
});
// ========== 4. 支付服务 (payment-service.js) ==========
// 端口: 3004
const express = require('express');
const app = express();
app.use(express.json());
const payments = [];
app.post('/payments', async (req, res) => {
const { userId, amount } = req.body;
// 调用外部支付API (例如: Stripe, Toss Payments)
try {
// 实际支付处理
const payment = {
id: payments.length + 1,
userId,
amount,
status: 'success',
createdAt: new Date()
};
payments.push(payment);
// 发布事件
await publishEvent('payment.completed', payment);
res.json(payment);
} catch (error) {
res.status(400).json({ error: '支付失败' });
}
});
app.listen(3004, () => {
console.log('支付服务: http://localhost:3004');
});
// ========== 5. API Gateway (gateway.js) ==========
// 端口: 3000
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// 认证中间件
function authenticate(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: '需要认证' });
}
// JWT验证等
next();
}
// 日志中间件
app.use((req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
});
// 用户服务代理
app.use('/api/users', authenticate, createProxyMiddleware({
target: 'http://localhost:3001',
pathRewrite: { '^/api/users': '/users' },
changeOrigin: true
}));
// 商品服务代理
app.use('/api/products', createProxyMiddleware({
target: 'http://localhost:3002',
pathRewrite: { '^/api/products': '/products' },
changeOrigin: true
}));
// 订单服务代理
app.use('/api/orders', authenticate, createProxyMiddleware({
target: 'http://localhost:3003',
pathRewrite: { '^/api/orders': '/orders' },
changeOrigin: true
}));
// 支付服务代理
app.use('/api/payments', authenticate, createProxyMiddleware({
target: 'http://localhost:3004',
pathRewrite: { '^/api/payments': '/payments' },
changeOrigin: true
}));
app.listen(3000, () => {
console.log('API Gateway: http://localhost:3000');
});
// ========== 6. 事件总线 (event-bus.js) ==========
const amqp = require('amqplib');
let connection, channel;
// 连接 RabbitMQ
async function connect() {
connection = await amqp.connect('amqp://localhost');
channel = await connection.createChannel();
}
// 发布事件
async function publishEvent(eventType, data) {
await channel.assertQueue(eventType);
channel.sendToQueue(
eventType,
Buffer.from(JSON.stringify(data))
);
console.log(`事件发布: ${eventType}`, data);
}
// 订阅事件
async function subscribeEvent(eventType, callback) {
await channel.assertQueue(eventType);
channel.consume(eventType, (msg) => {
const data = JSON.parse(msg.content.toString());
console.log(`事件接收: ${eventType}`, data);
callback(data);
channel.ack(msg);
});
}
connect();
module.exports = { publishEvent, subscribeEvent };
使用 Docker Compose 运行微服务
# docker-compose.yml
version: '3.8'
services:
# API Gateway
gateway:
build: ./gateway
ports:
- "3000:3000"
depends_on:
- user-service
- product-service
- order-service
- payment-service
# 用户服务
user-service:
build: ./user-service
ports:
- "3001:3001"
environment:
- MONGO_URL=mongodb://mongo:27017/users
depends_on:
- mongo
- rabbitmq
# 商品服务
product-service:
build: ./product-service
ports:
- "3002:3002"
environment:
- POSTGRES_URL=postgres://postgres:password@postgres:5432/products
depends_on:
- postgres
- rabbitmq
# 订单服务
order-service:
build: ./order-service
ports:
- "3003:3003"
environment:
- MYSQL_URL=mysql://root:password@mysql:3306/orders
depends_on:
- mysql
- rabbitmq
# 支付服务
payment-service:
build: ./payment-service
ports:
- "3004:3004"
depends_on:
- rabbitmq
# 数据库
mongo:
image: mongo:6
volumes:
- mongo-data:/data/db
postgres:
image: postgres:15
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=products
volumes:
- postgres-data:/var/lib/postgresql/data
mysql:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=orders
volumes:
- mysql-data:/var/lib/mysql
# 消息队列
rabbitmq:
image: rabbitmq:3-management
ports:
- "5672:5672"
- "15672:15672" # 管理UI
volumes:
mongo-data:
postgres-data:
mysql-data:
Service Mesh (Istio 示例)
# istio-config.yaml
# 服务网格 - 管理服务间通信
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
# 流量分配(金丝雀部署)
- match:
- headers:
user-type:
exact: beta
route:
- destination:
host: order-service
subset: v2 # 新版本
weight: 20
- destination:
host: order-service
subset: v1 # 现有版本
weight: 80
# 重试策略
- route:
- destination:
host: order-service
retries:
attempts: 3
perTryTimeout: 2s
# 超时
timeout: 10s
---
# Circuit Breaker
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: payment-service
spec:
host: payment-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
🤔 常见问题
Q1. 什么时候应该使用微服务?
A:
✅ 适合使用微服务的情况:
1. 大规模应用程序
- 团队: 10人以上
- 代码: 10万行以上
- 用户: 数十万以上
2. 需要快速部署
- 每天多次部署
- 独立功能发布
- 频繁A/B测试
3. 需要多样化技术栈
- 每个服务选择最优技术
- 与遗留系统集成
4. 需要独立扩展
- 特定功能流量大
- 每个服务资源需求不同
5. 团队独立性重要
- 多个团队同时开发
- 最小化团队间依赖
示例:
- Netflix: 数百个微服务
- Amazon: 2-pizza团队(每个团队负责一个服务)
- Uber: 按地区和功能分离服务
❌ 适合使用单体架构的情况:
1. 小型应用程序
- 团队: 5人或更少
- 功能: 清晰简单
- 流量: 较低
2. 早期创业公司
- 需要快速MVP开发
- 需求频繁变化
- 资源有限
3. 简单CRUD
- 没有复杂业务逻辑
- 服务边界不清晰
4. 缺乏运维经验
- 没有DevOps团队
- 没有分布式系统经验
示例:
- 博客、作品集
- 小型电商
- 内部工具
📊 决策检查清单:
□ 团队规模10人以上?
□ 代码库10万行以上?
□ 需要频繁独立部署?
□ 需要部分扩展?
□ 有DevOps团队?
□ 有分布式系统经验?
3个或以上 → 考虑微服务
2个或以下 → 保持单体架构
Q2. 微服务的最大挑战是什么?
A:
// ========== 1. 分布式事务 ==========
// 单体架构: 简单事务
await db.transaction(async (t) => {
await createOrder(data, t);
await decreaseStock(productId, t);
await processPayment(amount, t);
// 任何失败都会回滚整个事务
});
// 微服务: 复杂的Saga模式
async function createOrderSaga(data) {
try {
// 步骤1
const order = await orderService.create(data);
// 步骤2
await productService.decreaseStock(data.productId);
// 步骤3
await paymentService.process(order.total);
return order;
} catch (error) {
// 补偿事务(反向顺序)
await paymentService.refund(order.total);
await productService.increaseStock(data.productId);
await orderService.cancel(order.id);
throw error;
}
}
// ========== 2. 数据一致性 ==========
// 问题: 数据分散在多个服务中
// 用户服务: userId, name
// 订单服务: userId, orders
// 支付服务: userId, payments
// 解决方案1: 事件溯源
eventBus.on('user.updated', async (event) => {
// 当用户信息改变时,更新其他服务
await orderService.updateUserInfo(event.userId, event.name);
await paymentService.updateUserInfo(event.userId, event.name);
});
// 解决方案2: CQRS (命令查询职责分离)
// 分离写入和读取
// 写入: 各服务独立
// 读取: 统一视图(读模型)
// ========== 3. 网络延迟 ==========
// 单体架构: 函数调用(快)
const user = getUser(userId); // 1ms
// 微服务: HTTP请求(慢)
const user = await axios.get(`http://user-service/users/${userId}`); // 50ms
// 解决方案: 缓存
const redis = require('redis');
const cache = redis.createClient();
async function getUser(userId) {
// 1. 检查缓存
const cached = await cache.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
// 2. 调用服务
const response = await axios.get(`http://user-service/users/${userId}`);
const user = response.data;
// 3. 保存到缓存
await cache.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
// ========== 4. 服务故障处理 ==========
// 断路器模式
const CircuitBreaker = require('opossum');
const options = {
timeout: 3000, // 3秒超时
errorThresholdPercentage: 50, // 50%失败时
resetTimeout: 30000 // 30秒后重试
};
const breaker = new CircuitBreaker(async (userId) => {
return await axios.get(`http://user-service/users/${userId}`);
}, options);
breaker.fallback(() => ({
id: userId,
name: '未知', // 降级数据
cached: true
}));
// 使用
breaker.fire(userId)
.then(console.log)
.catch(console.error);
// ========== 5. 监控和调试 ==========
// 分布式追踪
// 使用 Jaeger, Zipkin
const tracer = require('jaeger-client').initTracer(config);
app.use((req, res, next) => {
const span = tracer.startSpan('http_request');
span.setTag('http.method', req.method);
span.setTag('http.url', req.url);
req.span = span;
next();
});
// 服务间调用时传递追踪ID
await axios.get('http://order-service/orders', {
headers: {
'x-trace-id': req.span.context().toTraceId()
}
});
Q3. API Gateway的作用是什么?
A:
// ========== API Gateway 主要功能 ==========
const express = require('express');
const rateLimit = require('express-rate-limit');
const jwt = require('jsonwebtoken');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// ========== 1. 路由 ==========
// 客户端只需要知道一个端点
app.use('/api/users', createProxyMiddleware({
target: 'http://user-service:3001',
changeOrigin: true
}));
app.use('/api/products', createProxyMiddleware({
target: 'http://product-service:3002',
changeOrigin: true
}));
// ========== 2. 认证和授权 ==========
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: '需要令牌' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: '无效令牌' });
}
}
app.use('/api/orders', authenticate, createProxyMiddleware({
target: 'http://order-service:3003'
}));
// ========== 3. 限流 ==========
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 最多100个请求
});
app.use('/api/', limiter);
// ========== 4. 负载均衡 ==========
const productServiceInstances = [
'http://product-service-1:3002',
'http://product-service-2:3002',
'http://product-service-3:3002'
];
let currentIndex = 0;
app.use('/api/products', createProxyMiddleware({
target: productServiceInstances[currentIndex],
router: () => {
// 轮询
const target = productServiceInstances[currentIndex];
currentIndex = (currentIndex + 1) % productServiceInstances.length;
return target;
}
}));
// ========== 5. 请求/响应转换 ==========
app.use('/api/legacy', createProxyMiddleware({
target: 'http://legacy-service:8080',
onProxyReq: (proxyReq, req) => {
// 转换请求
proxyReq.setHeader('X-API-Version', '2.0');
},
onProxyRes: (proxyRes, req, res) => {
// 转换响应
proxyRes.headers['X-Custom-Header'] = 'Gateway';
}
}));
// ========== 6. 缓存 ==========
const redis = require('redis');
const cache = redis.createClient();
app.get('/api/products/:id', async (req, res) => {
const cacheKey = `product:${req.params.id}`;
// 检查缓存
const cached = await cache.get(cacheKey);
if (cached) {
return res.json(JSON.parse(cached));
}
// 调用服务
const response = await axios.get(
`http://product-service:3002/products/${req.params.id}`
);
// 保存到缓存
await cache.setex(cacheKey, 3600, JSON.stringify(response.data));
res.json(response.data);
});
// ========== 7. 日志和监控 ==========
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log({
method: req.method,
path: req.path,
status: res.statusCode,
duration: `${duration}ms`,
user: req.user?.id
});
});
next();
});
// ========== 8. 错误处理 ==========
app.use((err, req, res, next) => {
console.error('Gateway Error:', err);
if (err.code === 'ECONNREFUSED') {
return res.status(503).json({
error: '服务不可用'
});
}
res.status(500).json({
error: '发生服务器错误'
});
});
// ========== 9. 服务发现 ==========
const consul = require('consul')();
async function getServiceUrl(serviceName) {
const result = await consul.health.service({
service: serviceName,
passing: true // 只有通过健康检查的实例
});
if (result.length === 0) {
throw new Error(`未找到${serviceName}服务`);
}
// 随机选择
const instance = result[Math.floor(Math.random() * result.length)];
return `http://${instance.Service.Address}:${instance.Service.Port}`;
}
app.listen(3000);
Q4. 微服务部署策略有哪些?
A:
# ========== 1. 蓝绿部署 ==========
# 部署新版本(绿色)并一次性切换流量
# 蓝色(当前版本)
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
version: blue # 当前流量
ports:
- port: 80
---
# 部署绿色(新版本)
kubectl apply -f order-service-green.yaml
# 测试后切换流量
kubectl patch service order-service -p '{"spec":{"selector":{"version":"green"}}}'
# 如有问题立即回滚
kubectl patch service order-service -p '{"spec":{"selector":{"version":"blue"}}}'
# ========== 2. 金丝雀部署 ==========
# 只向新版本发送部分流量并逐步增加
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
- route:
- destination:
host: order-service
subset: v1 # 现有版本
weight: 90 # 90%流量
- destination:
host: order-service
subset: v2 # 新版本
weight: 10 # 10%流量
# 逐步增加
# 10% → 25% → 50% → 75% → 100%
# ========== 3. 滚动更新 ==========
# Kubernetes 默认策略
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多额外创建1个
maxUnavailable: 1 # 最多允许1个不可用
template:
spec:
containers:
- name: order-service
image: order-service:v2
# 顺序:
# 1. 启动1个新Pod
# 2. 健康检查通过后终止1个旧Pod
# 3. 重复(直到全部5个被替换)
# ========== 4. Docker Compose 部署 ==========
# docker-compose.yml
version: '3.8'
services:
order-service:
image: order-service:latest
deploy:
replicas: 3
update_config:
parallelism: 1 # 一次1个
delay: 10s # 10秒间隔
failure_action: rollback # 失败时回滚
restart_policy:
condition: on-failure
# 部署
docker stack deploy -c docker-compose.yml myapp
# ========== 5. CI/CD 流水线 ==========
# .github/workflows/deploy.yml
name: Deploy Microservices
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# 检测变更的服务
- name: 检测变更的服务
uses: dorny/paths-filter@v2
id: changes
with:
filters: |
user-service:
- 'services/user/**'
product-service:
- 'services/product/**'
- name: 部署用户服务
if: steps.changes.outputs.user-service == 'true'
run: |
docker build -t user-service:${{ github.sha }} services/user
docker push user-service:${{ github.sha }}
kubectl set image deployment/user-service user-service=user-service:${{ github.sha }}
- name: 部署商品服务
if: steps.changes.outputs.product-service == 'true'
run: |
docker build -t product-service:${{ github.sha }} services/product
docker push product-service:${{ github.sha }}
kubectl set image deployment/product-service product-service=product-service:${{ github.sha }}
Q5. 如何从单体架构迁移到微服务?
A:
// ========== 分步迁移策略 ==========
// ========== 步骤1: Strangler Fig 模式 ==========
// 新功能作为微服务,保持现有功能
┌─────────────────────────────────┐
│ 单体应用程序 │
│ ┌────── ────┬──────────┬──────┐ │
│ │用户管理 │商品管理 │订单 │ │
│ │ │ │管理 │ │
│ └──────────┴──────────┴──────┘ │
└─────────────────────────────────┘
// 步骤1: 新功能(通知)作为微服务
┌─────────────────────┐ ┌──────────────┐
│ 单体架构 │ │通知服务 │
│ 用户│商品│订单 │ │(新建) │
└─────────────────────┘ └── ────────────┘
// 步骤2: 提取订单功能
┌─────────────────────┐ ┌──────────────┐
│ 单体架构 │ │订单服务 │
│ 用户│商品 │ │(提取) │
└─────────────────────┘ └──────────────┘
┌──────────────┐
│通知服务 │
└──────────────┘
// 步骤3: 提取所有功能
┌──────────┐ ┌──────────┐ ┌──────────┐
│用户 │ │商品 │ │订单 │
│服务 │ │服务 │ │服务 │
└──────────┘ └──────────┘ └──────────┘
┌──────────┐
│通知服务 │
└──────────┘
// ========== 步骤2: 引入 API Gateway ==========
// 之前: 客户端直接调用单体
const response = await fetch('http://monolith/api/orders');
// 之后: 通过 API Gateway 调用
const response = await fetch('http://api-gateway/api/orders');
// API Gateway 路由
if (route === '/api/orders') {
// 路由到新服务
proxy('http://order-service/orders');
} else {
// 仍然到单体
proxy('http://monolith/api');
}
// ========== 步骤3: 数据库分离 ==========
// 问题: 共享数据库
┌────────────────┐
│ 单体数据库 │
│ ┌──────────┐ │
│ │Users │ │
│ │Products │ │
│ │Orders │ │
│ └──────────┘ │
└────────────────┘
// 解决方案: 每个服务一个数据库
// 1) 双写 (Dual Write)
async function createOrder(data) {
// 写入单体数据库
await monolithDB.orders.create(data);
// 写入新服务数据库
await orderServiceDB.orders.create(data);
}
// 2) 变更数据捕获 (CDC)
// 自动同步单体数据库的变更
const debezium = require('debezium');
debezium.on('orders.insert', async (change) => {
// 反映到新服务数据库
await orderServiceDB.orders.create(change.data);
});
// 3) 完全分离
┌──────────┐ ┌──────────┐ ┌──────────┐
│Users DB │ │Products │ │Orders DB │
│(MongoDB) │ │DB(MySQL) │ │(Postgres)│
└──────────┘ └──────────┘ └──────────┘
// ========== 步骤4: 逐步切换流量 ==========
// 在 API Gateway 中调整比例
const MIGRATION_PERCENTAGE = 10; // 只有10%到新服务
app.use('/api/orders', (req, res, next) => {
if (Math.random() * 100 < MIGRATION_PERCENTAGE) {
// 到新服务
proxy('http://order-service/orders')(req, res, next);
} else {
// 到单体
proxy('http://monolith/api/orders')(req, res, next);
}
});
// 逐步增加
// 10% → 25% → 50% → 75% → 100%
// ========== 步骤5: 监控和回滚准备 ==========
const NEW_SERVICE_ERROR_THRESHOLD = 0.05; // 5%错误率
async function monitorNewService() {
const errorRate = await getErrorRate('order-service');
if (errorRate > NEW_SERVICE_ERROR_THRESHOLD) {
// 错误率高则回滚
console.error('错误率高!回滚到单体');
MIGRATION_PERCENTAGE = 0;
// 警报
await sendAlert('迁移回滚发生');
}
}
// ========== 实践检查清单 ==========
迁移检查清单:
□ 1. 识别边界
- 领域驱动设计 (DDD)
- 按业务功能划分
□ 2. 从最独立的功能开始
- 依赖少的
- 业务影响小的
- 例如: 通知、日志、搜索
□ 3. 引入 API Gateway
- 逐步切换流量
□ 4. 数据库分离策略
- 双写 → CDC → 完全分离
□ 5. 增强监控
- 错误率、响应时间、流量
- 准备回滚
□ 6. 团队培训
- 微服务架构
- DevOps 工具 (Docker, Kubernetes)
□ 7. 文档化
- 服务目录
- API 文档
- 部署指南
🎓 下一步
了解微服务架构后,学习:
- 什么是Docker? (待创建文档) - 容器化
- 什么是CI/CD? - 自动化部署
- REST API vs GraphQL - API 设计
实践
# ========== 1. 简单微服务实践 ==========
# 项目结构
mkdir microservices-demo
cd microservices-demo
# 创建服务
mkdir -p services/{user,product,order}
mkdir gateway
# 编写 Docker Compose
cat > docker-compose.yml
# 运行
docker-compose up -d
# 检查日志
docker-compose logs -f
# ========== 2. Kubernetes 部署 ==========
# 安装 minikube (本地 K8s)
brew install minikube
minikube start
# 部署
kubectl apply -f kubernetes/
# 检查服务
kubectl get pods
kubectl get services
# 检查日志
kubectl logs <pod-name>
# ========== 3. 安装 Istio (Service Mesh) ==========
# 安装 Istio
istioctl install --set profile=demo -y
# 向服务注入 sidecar
kubectl label namespace default istio-injection=enabled
# Istio 仪表板
istioctl dashboard kiali
🎬 结论
微服务架构提供可扩展性和灵活性:
- 独立性: 每个服务独立开发、部署、扩展
- 技术多样性: 每个服务选择最优技术
- 故障隔离: 一个服务故障不影响整体
- 团队自治: 每个团队负责服务
但是复杂度会增加,所以要根据项目规模和团队能力选择! 🧩