跳至正文

🧩 微服务架构

📖 定义

微服务架构(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 文档
- 部署指南

🎓 下一步

了解微服务架构后,学习:

  1. 什么是Docker? (待创建文档) - 容器化
  2. 什么是CI/CD? - 自动化部署
  3. 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

🎬 结论

微服务架构提供可扩展性和灵活性:

  • 独立性: 每个服务独立开发、部署、扩展
  • 技术多样性: 每个服务选择最优技术
  • 故障隔离: 一个服务故障不影响整体
  • 团队自治: 每个团队负责服务

但是复杂度会增加,所以要根据项目规模和团队能力选择! 🧩