微服务测试项目架构设计与实践
📋 项目背景
在4C8G的有限资源环境下,设计并实现了一套轻量级微服务测试项目,用于验证微服务架构的测试策略和最佳实践。
核心挑战:
- 资源受限(4核8G)
- 服务间通信复杂
- 测试数据隔离
- 健康监控需求
🏗️ 架构设计
整体架构
┌─────────────────────────────────────┐
│ API Gateway │
│ Port: 3000 │
│ ┌──────────────┬──────────────┐ │
│ │ /api/users │ /api/orders │ │
│ └──────┬───────┴──────┬───────┘ │
└─────────┼──────────────┼───────────┘
│ │
┌─────┘ └─────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ User Service│ │Order Service│
│ Port: 3001 │ │ Port: 3002 │
│ Memory: │ │ Memory: │
│ 256MB │ │ 256MB │
│ Max: 100 │ │ Max: 100 │
│ users │ │ orders │
└─────────────┘ └─────────────┘
服务职责
| 服务 | 端口 | 职责 | 内存限制 |
|---|---|---|---|
| Gateway | 3000 | 路由转发、聚合查询、健康检查 | 256MB |
| User Service | 3001 | 用户CRUD、统计信息 | 256MB |
| Order Service | 3002 | 订单CRUD、状态管理 | 256MB |
💡 核心设计决策
1. 内存优化策略
问题:Node.js 默认内存无限制,容易OOM
解决方案:
javascript
// 启动时设置内存限制
node --max-old-space-size=256 service.js
// 代码中主动监控
const logMemoryUsage = () => {
const usage = process.memoryUsage();
console.log(`Memory: ${Math.round(usage.heapUsed / 1024 / 1024)}MB`);
};
setInterval(logMemoryUsage, 30000);
数据限制:
- 最大用户数:100
- 最大订单数:100
- 超出自动清理最旧数据
2. 服务发现简化
传统方案:使用 Consul/Eureka,资源消耗大
我们的方案:硬编码 + 健康检查
javascript
// gateway.js
const SERVICES = {
users: { url: 'http://localhost:3001', healthy: true },
orders: { url: 'http://localhost:3002', healthy: true }
};
// 定时健康检查
setInterval(checkServicesHealth, 30000);
3. 数据存储策略
传统方案:MySQL/Redis,增加复杂度
我们的方案:内存存储 + 数据持久化接口
javascript
// 内存存储
const users = new Map();
const orders = new Map();
// 预留持久化接口
class DataStore {
async save(key, data) { /* 可接入Redis/DB */ }
async load(key) { /* 可接入Redis/DB */ }
}
🔧 核心代码实现
API Gateway 路由转发
javascript
// 动态路由到用户服务
app.use('/api/users', async (req, res) => {
try {
const targetUrl = `${SERVICES.users.url}${req.path}`;
const response = await axios({
method: req.method,
url: targetUrl,
data: req.body,
headers: req.headers
});
res.status(response.status).json(response.data);
} catch (error) {
res.status(502).json({ error: 'User service unavailable' });
}
});
聚合查询实现
javascript
// GET /api/users/:id/orders
app.get('/api/users/:id/orders', async (req, res) => {
const userId = req.params.id;
// 并行查询
const [userRes, ordersRes] = await Promise.all([
axios.get(`${SERVICES.users.url}/users/${userId}`),
axios.get(`${SERVICES.orders.url}/orders?userId=${userId}`)
]);
res.json({
user: userRes.data,
orders: ordersRes.data.orders
});
});
健康检查机制
javascript
// 服务健康检查
app.get('/health', async (req, res) => {
const checks = await Promise.all([
checkService('users'),
checkService('orders')
]);
const allHealthy = checks.every(c => c.healthy);
res.status(allHealthy ? 200 : 503).json({
status: allHealthy ? 'UP' : 'DEGRADED',
services: {
users: checks[0],
orders: checks[1]
},
timestamp: new Date().toISOString()
});
});
🧪 测试策略
健康检查测试
javascript
// 6个核心健康检查测试
describe('Health Checks', () => {
test('Gateway Health', async () => {
const res = await axios.get('http://localhost:3000/health');
expect(res.status).toBe(200);
expect(res.data.status).toBe('UP');
});
test('User Service Health', async () => {
const res = await axios.get('http://localhost:3001/health');
expect(res.data.service).toBe('user-service');
});
test('Order Service Health', async () => {
const res = await axios.get('http://localhost:3002/health');
expect(res.data.service).toBe('order-service');
});
});
集成测试
javascript
// 端到端流程测试
test('Complete User-Order Flow', async () => {
// 1. 创建用户
const user = await axios.post('/api/users', {
name: '测试用户',
email: 'test@example.com'
});
// 2. 创建订单
const order = await axios.post('/api/orders', {
userId: user.data.id,
items: [{ name: '商品', price: 100 }],
totalAmount: 100
});
// 3. 聚合查询
const aggregate = await axios.get(`/api/users/${user.data.id}/orders`);
expect(aggregate.data.orders).toHaveLength(1);
});
📊 性能数据
资源占用
| 指标 | Gateway | User | Order | 总计 |
|---|---|---|---|---|
| 内存 | ~45MB | ~40MB | ~40MB | ~125MB |
| 启动时间 | 1.2s | 0.8s | 0.8s | - |
| 响应时间 | <50ms | <30ms | <30ms | <100ms |
测试结果
✅ 6/6 健康检查通过 (100%)
- Gateway Health: 200
- User Service Health: 200
- Order Service Health: 200
- Gateway Stats: 200
- User List: 200
- Order List: 200
🎯 最佳实践总结
1. 资源受限环境的设计原则
- ✅ 内存优先:设置硬性限制,主动监控
- ✅ 简化架构:去除不必要的组件(注册中心、消息队列)
- ✅ 预留扩展:接口设计考虑未来接入外部存储
2. 微服务测试要点
- ✅ 契约测试:验证服务间接口契约
- ✅ 健康检查:每个服务暴露/health端点
- ✅ 故障注入:模拟服务宕机,测试降级策略
- ✅ 数据隔离:测试数据与生产数据分离
3. 部署与运维
bash
# 一键启动所有服务
npm run start:all
# 健康检查
npm run test:health
# 停止所有服务
npm run stop:all
🚀 后续规划
- 接入 Redis 实现分布式缓存
- 添加 JWT 认证和权限控制
- 实现熔断和限流机制
- 接入 Prometheus 监控
- 容器化部署(Docker + K8s)
📁 项目地址
test-projects/microservices-demo/
├── services/
│ ├── gateway.js # API网关
│ ├── user-service.js # 用户服务
│ └── order-service.js # 订单服务
├── tests/
│ ├── integration/ # 集成测试
│ └── unit/ # 单元测试
├── run-tests.js # 测试运行器
└── package.json
💬 总结
在资源受限的环境下,通过合理的架构设计和优化策略,我们成功构建了一套轻量级但功能完整的微服务测试项目。核心经验:简化不等于简陋,预留扩展空间,关注可测试性。