云原生架构设计与实践

概述

云原生(Cloud Native)是一种构建和运行应用程序的方法,充分利用云计算的优势。本文将深入探讨云原生架构的核心概念、设计原则和实践方法。

云原生的核心特征

  1. 容器化 - 应用程序打包为容器
  2. 微服务架构 - 松耦合的服务组合
  3. 动态编排 - 自动化部署和管理
  4. DevOps文化 - 开发和运维的协作
  5. 持续交付 - 快速、可靠的软件发布

1. 容器化技术

Docker容器化实践

多阶段构建优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Dockerfile - 多阶段构建示例
# 构建阶段
FROM node:18-alpine AS builder

WORKDIR /app

# 复制依赖文件
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# 复制源代码
COPY . .

# 构建应用
RUN npm run build

# 生产阶段
FROM node:18-alpine AS production

# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001

WORKDIR /app

# 复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json

# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000

# 暴露端口
EXPOSE 3000

# 切换到非root用户
USER nextjs

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1

# 启动应用
CMD ["node", "dist/index.js"]

容器安全最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 安全容器构建
FROM node:18-alpine

# 更新系统包
RUN apk update && apk upgrade && \
apk add --no-cache dumb-init && \
rm -rf /var/cache/apk/*

# 创建应用目录和用户
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup

WORKDIR /app

# 设置正确的权限
RUN chown -R appuser:appgroup /app

# 复制文件并设置权限
COPY --chown=appuser:appgroup package*.json ./
USER appuser

# 安装依赖
RUN npm ci --only=production && npm cache clean --force

# 复制应用代码
COPY --chown=appuser:appgroup . .

# 安全配置
ENV NODE_ENV=production
ENV NPM_CONFIG_LOGLEVEL=warn

# 使用dumb-init作为PID 1
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "index.js"]

容器编排与管理

Docker Compose服务编排

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# docker-compose.yml - 完整的应用栈
version: '3.8'

services:
# 前端应用
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
target: production
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- API_URL=http://backend:8080
depends_on:
- backend
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3

# 后端API
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@postgres:5432/myapp
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
volumes:
- ./logs:/app/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3

# 数据库
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5

# 缓存
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3

# 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- frontend
- backend
networks:
- app-network
restart: unless-stopped

# 监控
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
networks:
- app-network
restart: unless-stopped

grafana:
image: grafana/grafana:latest
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
networks:
- app-network
restart: unless-stopped

volumes:
postgres_data:
redis_data:
prometheus_data:
grafana_data:

networks:
app-network:
driver: bridge

2. 微服务架构设计

服务拆分策略

领域驱动设计 (DDD) 实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// userService.js - 用户服务
const express = require('express');
const { body, validationResult } = require('express-validator');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const rateLimit = require('express-rate-limit');

class UserService {
constructor(database, eventBus, logger) {
this.db = database;
this.eventBus = eventBus;
this.logger = logger;
this.app = express();
this.setupMiddleware();
this.setupRoutes();
}

setupMiddleware() {
this.app.use(express.json({ limit: '10mb' }));
this.app.use(express.urlencoded({ extended: true }));

// 限流中间件
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 100次请求
message: 'Too many requests from this IP'
});
this.app.use(limiter);

// 请求日志
this.app.use((req, res, next) => {
this.logger.info(`${req.method} ${req.path}`, {
ip: req.ip,
userAgent: req.get('User-Agent')
});
next();
});
}

setupRoutes() {
// 健康检查
this.app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
service: 'user-service',
version: process.env.SERVICE_VERSION || '1.0.0'
});
});

// 用户注册
this.app.post('/users/register', [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
body('username').isLength({ min: 3, max: 30 }).isAlphanumeric()
], this.registerUser.bind(this));

// 用户登录
this.app.post('/users/login', [
body('email').isEmail().normalizeEmail(),
body('password').notEmpty()
], this.loginUser.bind(this));

// 获取用户信息
this.app.get('/users/:id', this.authenticateToken.bind(this), this.getUserById.bind(this));

// 更新用户信息
this.app.put('/users/:id', [
this.authenticateToken.bind(this),
body('username').optional().isLength({ min: 3, max: 30 }),
body('email').optional().isEmail().normalizeEmail()
], this.updateUser.bind(this));

// 删除用户
this.app.delete('/users/:id', this.authenticateToken.bind(this), this.deleteUser.bind(this));

// 错误处理
this.app.use(this.errorHandler.bind(this));
}

async registerUser(req, res) {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

const { email, password, username } = req.body;

// 检查用户是否已存在
const existingUser = await this.db.findUserByEmail(email);
if (existingUser) {
return res.status(409).json({ error: 'User already exists' });
}

// 加密密码
const hashedPassword = await bcrypt.hash(password, 12);

// 创建用户
const user = await this.db.createUser({
email,
password: hashedPassword,
username,
createdAt: new Date(),
isActive: true
});

// 发布用户创建事件
await this.eventBus.publish('user.created', {
userId: user.id,
email: user.email,
username: user.username,
timestamp: new Date().toISOString()
});

// 生成JWT令牌
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);

res.status(201).json({
message: 'User created successfully',
user: {
id: user.id,
email: user.email,
username: user.username
},
token
});

} catch (error) {
this.logger.error('Registration failed', error);
res.status(500).json({ error: 'Internal server error' });
}
}

async loginUser(req, res) {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

const { email, password } = req.body;

// 查找用户
const user = await this.db.findUserByEmail(email);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}

// 验证密码
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid credentials' });
}

// 检查用户状态
if (!user.isActive) {
return res.status(403).json({ error: 'Account is disabled' });
}

// 更新最后登录时间
await this.db.updateUserLastLogin(user.id);

// 发布登录事件
await this.eventBus.publish('user.logged_in', {
userId: user.id,
email: user.email,
timestamp: new Date().toISOString(),
ip: req.ip
});

// 生成JWT令牌
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);

res.json({
message: 'Login successful',
user: {
id: user.id,
email: user.email,
username: user.username
},
token
});

} catch (error) {
this.logger.error('Login failed', error);
res.status(500).json({ error: 'Internal server error' });
}
}

async getUserById(req, res) {
try {
const { id } = req.params;
const requestingUserId = req.user.userId;

// 权限检查:用户只能访问自己的信息或管理员可以访问所有用户
if (id !== requestingUserId && !req.user.isAdmin) {
return res.status(403).json({ error: 'Access denied' });
}

const user = await this.db.findUserById(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}

res.json({
user: {
id: user.id,
email: user.email,
username: user.username,
createdAt: user.createdAt,
lastLoginAt: user.lastLoginAt,
isActive: user.isActive
}
});

} catch (error) {
this.logger.error('Get user failed', error);
res.status(500).json({ error: 'Internal server error' });
}
}

async updateUser(req, res) {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

const { id } = req.params;
const requestingUserId = req.user.userId;

// 权限检查
if (id !== requestingUserId && !req.user.isAdmin) {
return res.status(403).json({ error: 'Access denied' });
}

const updateData = {};
if (req.body.username) updateData.username = req.body.username;
if (req.body.email) updateData.email = req.body.email;

// 检查邮箱是否已被使用
if (updateData.email) {
const existingUser = await this.db.findUserByEmail(updateData.email);
if (existingUser && existingUser.id !== id) {
return res.status(409).json({ error: 'Email already in use' });
}
}

const updatedUser = await this.db.updateUser(id, updateData);
if (!updatedUser) {
return res.status(404).json({ error: 'User not found' });
}

// 发布用户更新事件
await this.eventBus.publish('user.updated', {
userId: id,
changes: updateData,
timestamp: new Date().toISOString()
});

res.json({
message: 'User updated successfully',
user: {
id: updatedUser.id,
email: updatedUser.email,
username: updatedUser.username
}
});

} catch (error) {
this.logger.error('Update user failed', error);
res.status(500).json({ error: 'Internal server error' });
}
}

async deleteUser(req, res) {
try {
const { id } = req.params;
const requestingUserId = req.user.userId;

// 权限检查
if (id !== requestingUserId && !req.user.isAdmin) {
return res.status(403).json({ error: 'Access denied' });
}

const user = await this.db.findUserById(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}

// 软删除:标记为非活跃状态
await this.db.updateUser(id, { isActive: false, deletedAt: new Date() });

// 发布用户删除事件
await this.eventBus.publish('user.deleted', {
userId: id,
email: user.email,
timestamp: new Date().toISOString()
});

res.json({ message: 'User deleted successfully' });

} catch (error) {
this.logger.error('Delete user failed', error);
res.status(500).json({ error: 'Internal server error' });
}
}

authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) {
return res.status(401).json({ error: 'Access token required' });
}

jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
req.user = user;
next();
});
}

errorHandler(error, req, res, next) {
this.logger.error('Unhandled error', error);

if (error.name === 'ValidationError') {
return res.status(400).json({ error: 'Validation failed', details: error.message });
}

if (error.name === 'JsonWebTokenError') {
return res.status(401).json({ error: 'Invalid token' });
}

res.status(500).json({ error: 'Internal server error' });
}

start(port = 3001) {
this.app.listen(port, () => {
this.logger.info(`User service started on port ${port}`);
});
}
}

module.exports = UserService;

服务间通信

事件驱动架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// eventBus.js - 事件总线实现
const EventEmitter = require('events');
const Redis = require('ioredis');

class EventBus extends EventEmitter {
constructor(redisConfig) {
super();
this.redis = new Redis(redisConfig);
this.subscriber = new Redis(redisConfig);
this.setupSubscriber();
}

setupSubscriber() {
this.subscriber.on('message', (channel, message) => {
try {
const event = JSON.parse(message);
this.emit(event.type, event.data);
} catch (error) {
console.error('Failed to parse event message:', error);
}
});
}

async publish(eventType, data) {
const event = {
id: this.generateEventId(),
type: eventType,
data,
timestamp: new Date().toISOString(),
version: '1.0'
};

try {
// 发布到Redis
await this.redis.publish('events', JSON.stringify(event));

// 存储事件到事件存储
await this.storeEvent(event);

// 本地触发事件
this.emit(eventType, data);

console.log(`Event published: ${eventType}`, event.id);
} catch (error) {
console.error('Failed to publish event:', error);
throw error;
}
}

subscribe(eventType, handler) {
this.on(eventType, handler);

// 订阅Redis频道
this.subscriber.subscribe('events');
}

async storeEvent(event) {
const key = `events:${event.type}:${event.id}`;
await this.redis.setex(key, 86400, JSON.stringify(event)); // 24小时过期
}

generateEventId() {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}

async getEventHistory(eventType, limit = 100) {
const pattern = `events:${eventType}:*`;
const keys = await this.redis.keys(pattern);
const events = [];

for (const key of keys.slice(0, limit)) {
const eventData = await this.redis.get(key);
if (eventData) {
events.push(JSON.parse(eventData));
}
}

return events.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
}
}

module.exports = EventBus;

API网关实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// apiGateway.js - API网关
const express = require('express');
const httpProxy = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const jwt = require('jsonwebtoken');
const Redis = require('ioredis');

class ApiGateway {
constructor(config) {
this.app = express();
this.config = config;
this.redis = new Redis(config.redis);
this.setupMiddleware();
this.setupRoutes();
}

setupMiddleware() {
// 请求日志
this.app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});

// CORS
this.app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});

// 全局限流
const globalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 1000, // 每个IP限制1000次请求
message: 'Too many requests from this IP',
standardHeaders: true,
legacyHeaders: false,
});
this.app.use(globalLimiter);

// 请求体解析
this.app.use(express.json({ limit: '10mb' }));
this.app.use(express.urlencoded({ extended: true }));
}

setupRoutes() {
// 健康检查
this.app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
gateway: 'api-gateway',
version: '1.0.0'
});
});

// 认证路由(不需要token)
this.app.use('/api/auth', this.createProxy('user-service', {
pathRewrite: { '^/api/auth': '/users' }
}));

// 用户服务路由
this.app.use('/api/users',
this.authenticateToken.bind(this),
this.createProxy('user-service', {
pathRewrite: { '^/api/users': '/users' }
})
);

// 订单服务路由
this.app.use('/api/orders',
this.authenticateToken.bind(this),
this.createProxy('order-service', {
pathRewrite: { '^/api/orders': '/orders' }
})
);

// 产品服务路由
this.app.use('/api/products',
this.createProxy('product-service', {
pathRewrite: { '^/api/products': '/products' }
})
);

// 支付服务路由
this.app.use('/api/payments',
this.authenticateToken.bind(this),
this.createProxy('payment-service', {
pathRewrite: { '^/api/payments': '/payments' }
})
);

// 通知服务路由
this.app.use('/api/notifications',
this.authenticateToken.bind(this),
this.createProxy('notification-service', {
pathRewrite: { '^/api/notifications': '/notifications' }
})
);

// 404处理
this.app.use('*', (req, res) => {
res.status(404).json({ error: 'Route not found' });
});

// 错误处理
this.app.use(this.errorHandler.bind(this));
}

createProxy(serviceName, options = {}) {
const serviceConfig = this.config.services[serviceName];

if (!serviceConfig) {
throw new Error(`Service ${serviceName} not configured`);
}

const proxyOptions = {
target: `http://${serviceConfig.host}:${serviceConfig.port}`,
changeOrigin: true,
timeout: 30000,
proxyTimeout: 30000,
...options,

onError: (err, req, res) => {
console.error(`Proxy error for ${serviceName}:`, err.message);
res.status(503).json({
error: 'Service temporarily unavailable',
service: serviceName
});
},

onProxyReq: (proxyReq, req, res) => {
// 添加请求头
proxyReq.setHeader('X-Gateway-Request-Id', this.generateRequestId());
proxyReq.setHeader('X-Gateway-Timestamp', new Date().toISOString());

// 传递用户信息
if (req.user) {
proxyReq.setHeader('X-User-Id', req.user.userId);
proxyReq.setHeader('X-User-Email', req.user.email);
}
},

onProxyRes: (proxyRes, req, res) => {
// 记录响应
console.log(`${serviceName} responded with status: ${proxyRes.statusCode}`);
}
};

return httpProxy(proxyOptions);
}

async authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) {
return res.status(401).json({ error: 'Access token required' });
}

try {
// 检查token是否在黑名单中
const isBlacklisted = await this.redis.get(`blacklist:${token}`);
if (isBlacklisted) {
return res.status(401).json({ error: 'Token has been revoked' });
}

// 验证token
const user = jwt.verify(token, process.env.JWT_SECRET);
req.user = user;

// 更新用户活动时间
await this.redis.setex(`user:activity:${user.userId}`, 3600, new Date().toISOString());

next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(403).json({ error: 'Invalid token' });
}
}

generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

errorHandler(error, req, res, next) {
console.error('Gateway error:', error);

if (error.code === 'ECONNREFUSED') {
return res.status(503).json({ error: 'Service unavailable' });
}

if (error.code === 'ETIMEDOUT') {
return res.status(504).json({ error: 'Gateway timeout' });
}

res.status(500).json({ error: 'Internal gateway error' });
}

async start(port = 3000) {
this.app.listen(port, () => {
console.log(`API Gateway started on port ${port}`);
});
}
}

module.exports = ApiGateway;

3. Kubernetes容器编排

基础资源配置

Deployment和Service配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
labels:
app: user-service
version: v1
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
version: v1
spec:
serviceAccountName: user-service-sa
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
containers:
- name: user-service
image: myregistry/user-service:v1.2.3
imagePullPolicy: Always
ports:
- containerPort: 3001
name: http
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3001"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: user-service-secrets
key: database-url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: user-service-secrets
key: jwt-secret
- name: REDIS_URL
valueFrom:
configMapKeyRef:
name: user-service-config
key: redis-url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: config-volume
mountPath: /app/config
readOnly: true
- name: logs-volume
mountPath: /app/logs
volumes:
- name: config-volume
configMap:
name: user-service-config
- name: logs-volume
emptyDir: {}
imagePullSecrets:
- name: registry-secret

---
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: production
labels:
app: user-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 3001
protocol: TCP
name: http
selector:
app: user-service

---
apiVersion: v1
kind: ConfigMap
metadata:
name: user-service-config
namespace: production
data:
redis-url: "redis://redis-service:6379"
log-level: "info"
max-connections: "100"

---
apiVersion: v1
kind: Secret
metadata:
name: user-service-secrets
namespace: production
type: Opaque
data:
database-url: cG9zdGdyZXNxbDovL3VzZXI6cGFzc3dvcmRAcG9zdGdyZXM6NTQzMi9teWFwcA==
jwt-secret: bXlfc3VwZXJfc2VjcmV0X2p3dF9rZXk=

---
apiVersion: v1
kind: ServiceAccount
metadata:
name: user-service-sa
namespace: production

高级配置

HPA自动扩缩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# hpa.yaml - 水平Pod自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: user-service-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
selectPolicy: Max

---
# vpa.yaml - 垂直Pod自动扩缩容
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: user-service-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: user-service
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 1
memory: 1Gi
controlledResources: ["cpu", "memory"]

Ingress网络配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# ingress.yaml - 入口控制器配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- api.myapp.com
secretName: api-tls-secret
rules:
- host: api.myapp.com
http:
paths:
- path: /api/users(/|$)(.*)
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /api/orders(/|$)(.*)
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /api/products(/|$)(.*)
pathType: Prefix
backend:
service:
name: product-service
port:
number: 80
- path: /api/payments(/|$)(.*)
pathType: Prefix
backend:
service:
name: payment-service
port:
number: 80

---
# network-policy.yaml - 网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: user-service-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: user-service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: production
- podSelector:
matchLabels:
app: api-gateway
ports:
- protocol: TCP
port: 3001
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53

4. 服务网格 (Service Mesh)

Istio服务网格配置

流量管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# virtual-service.yaml - 虚拟服务配置
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-service-vs
namespace: production
spec:
hosts:
- user-service
- api.myapp.com
gateways:
- user-service-gateway
- mesh
http:
- match:
- headers:
canary:
exact: "true"
route:
- destination:
host: user-service
subset: canary
weight: 100
- match:
- uri:
prefix: "/users"
route:
- destination:
host: user-service
subset: stable
weight: 90
- destination:
host: user-service
subset: canary
weight: 10
fault:
delay:
percentage:
value: 0.1
fixedDelay: 5s
retries:
attempts: 3
perTryTimeout: 2s
retryOn: gateway-error,connect-failure,refused-stream
timeout: 10s

---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service-dr
namespace: production
spec:
host: user-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
http2MaxRequests: 100
maxRequestsPerConnection: 10
maxRetries: 3
consecutiveGatewayErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
loadBalancer:
simple: LEAST_CONN
outlierDetection:
consecutiveGatewayErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
minHealthPercent: 50
subsets:
- name: stable
labels:
version: v1
trafficPolicy:
circuitBreaker:
connectionPool:
tcp:
maxConnections: 50
http:
http1MaxPendingRequests: 25
maxRequestsPerConnection: 5
- name: canary
labels:
version: v2
trafficPolicy:
circuitBreaker:
connectionPool:
tcp:
maxConnections: 10
http:
http1MaxPendingRequests: 5
maxRequestsPerConnection: 2

---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: user-service-gateway
namespace: production
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: api-tls-secret
hosts:
- api.myapp.com
- port:
number: 80
name: http
protocol: HTTP
hosts:
- api.myapp.com
tls:
httpsRedirect: true

安全策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# security-policy.yaml - 安全策略配置
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT

---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: user-service-authz
namespace: production
spec:
selector:
matchLabels:
app: user-service
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/api-gateway-sa"]
to:
- operation:
methods: ["GET", "POST", "PUT", "DELETE"]
paths: ["/users/*"]
when:
- key: request.headers[authorization]
values: ["Bearer *"]
- from:
- source:
namespaces: ["monitoring"]
to:
- operation:
methods: ["GET"]
paths: ["/health", "/metrics"]

---
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: user-service-jwt
namespace: production
spec:
selector:
matchLabels:
app: user-service
jwtRules:
- issuer: "https://auth.myapp.com"
jwksUri: "https://auth.myapp.com/.well-known/jwks.json"
audiences:
- "user-service"
forwardOriginalToken: true

可观测性配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# telemetry.yaml - 遥测配置
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: user-service-metrics
namespace: production
spec:
selector:
matchLabels:
app: user-service
metrics:
- providers:
- name: prometheus
- overrides:
- match:
metric: ALL_METRICS
tagOverrides:
request_id:
value: "%{REQUEST_ID}"
user_id:
value: "%{REQUEST_HEADER_X_USER_ID}"
accessLogging:
- providers:
- name: otel
tracing:
- providers:
- name: jaeger

5. CI/CD流水线

GitHub Actions工作流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
# 代码质量检查
code-quality:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run ESLint
run: npm run lint

- name: Run Prettier
run: npm run format:check

- name: Type checking
run: npm run type-check

- name: Security audit
run: npm audit --audit-level=high

- name: License compliance
run: npx license-checker --onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC'

# 单元测试
unit-tests:
runs-on: ubuntu-latest
needs: code-quality
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run unit tests
run: npm run test:unit -- --coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
flags: unittests
name: codecov-umbrella

# 集成测试
integration-tests:
runs-on: ubuntu-latest
needs: unit-tests
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run database migrations
run: npm run db:migrate
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb

- name: Run integration tests
run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
REDIS_URL: redis://localhost:6379

# 构建Docker镜像
build-image:
runs-on: ubuntu-latest
needs: [unit-tests, integration-tests]
if: github.event_name == 'push'
outputs:
image-digest: ${{ steps.build.outputs.digest }}
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NODE_ENV=production
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}

- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: spdx-json
output-file: sbom.spdx.json

- name: Scan image for vulnerabilities
uses: anchore/scan-action@v3
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
fail-build: true
severity-cutoff: high

# 部署到开发环境
deploy-dev:
runs-on: ubuntu-latest
needs: build-image
if: github.ref == 'refs/heads/develop'
environment:
name: development
url: https://dev-api.myapp.com
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'

- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_DEV }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig

- name: Deploy to development
run: |
export KUBECONFIG=kubeconfig
kubectl set image deployment/user-service user-service=${{ needs.build-image.outputs.image-tag }} -n development
kubectl rollout status deployment/user-service -n development --timeout=300s

- name: Run smoke tests
run: |
npm run test:smoke
env:
API_URL: https://dev-api.myapp.com

# 部署到生产环境
deploy-prod:
runs-on: ubuntu-latest
needs: [build-image, deploy-dev]
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://api.myapp.com
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'

- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_PROD }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig

- name: Deploy to production (Blue-Green)
run: |
export KUBECONFIG=kubeconfig

# 创建新的部署版本
kubectl patch deployment user-service -p '{"spec":{"template":{"spec":{"containers":[{"name":"user-service","image":"${{ needs.build-image.outputs.image-tag }}"}]}}}}' -n production

# 等待部署完成
kubectl rollout status deployment/user-service -n production --timeout=600s

# 运行健康检查
kubectl wait --for=condition=ready pod -l app=user-service -n production --timeout=300s

- name: Run production smoke tests
run: |
npm run test:smoke:prod
env:
API_URL: https://api.myapp.com

- name: Notify deployment success
uses: 8398a7/action-slack@v3
with:
status: success
text: 'Production deployment successful! 🚀'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

# E2E测试
e2e-tests:
runs-on: ubuntu-latest
needs: deploy-dev
if: github.ref == 'refs/heads/develop'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Install Playwright
run: npx playwright install --with-deps

- name: Run E2E tests
run: npm run test:e2e
env:
BASE_URL: https://dev-api.myapp.com

- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

GitOps配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# argocd-application.yaml - ArgoCD应用配置
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests
targetRevision: HEAD
path: user-service
helm:
valueFiles:
- values-production.yaml
parameters:
- name: image.tag
value: "v1.2.3"
- name: replicaCount
value: "3"
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10

---
# rollout-strategy.yaml - 渐进式部署
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: user-service-rollout
namespace: production
spec:
replicas: 5
strategy:
canary:
maxSurge: "25%"
maxUnavailable: 0
analysis:
templates:
- templateName: success-rate
startingStep: 2
args:
- name: service-name
value: user-service
steps:
- setWeight: 20
- pause: {duration: 10s}
- setWeight: 40
- pause: {duration: 10s}
- analysis:
templates:
- templateName: success-rate
args:
- name: service-name
value: user-service
- setWeight: 60
- pause: {duration: 10s}
- setWeight: 80
- pause: {duration: 10s}
trafficRouting:
istio:
virtualService:
name: user-service-vs
routes:
- primary
destinationRule:
name: user-service-dr
canarySubsetName: canary
stableSubsetName: stable
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: myregistry/user-service:v1.2.3
ports:
- containerPort: 3001
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

---
# analysis-template.yaml - 分析模板
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
namespace: production
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 10s
count: 3
successCondition: result[0] >= 0.95
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{job="{{args.service-name}}",code!~"5.."}[2m])) /
sum(rate(http_requests_total{job="{{args.service-name}}"}[2m]))
- name: avg-response-time
interval: 10s
count: 3
successCondition: result[0] <= 0.5
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket{job="{{args.service-name}}"}[2m])) by (le)
)

6. 监控和可观测性

Prometheus监控配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: monitoring
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'production'
region: 'us-west-2'

rule_files:
- "/etc/prometheus/rules/*.yml"

alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093

scrape_configs:
# Kubernetes API Server
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https

# Kubernetes Nodes
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)

# Kubernetes Pods
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name

# Application Services
- job_name: 'user-service'
static_configs:
- targets: ['user-service:80']
metrics_path: /metrics
scrape_interval: 10s

- job_name: 'order-service'
static_configs:
- targets: ['order-service:80']
metrics_path: /metrics
scrape_interval: 10s

alerts.yml: |
groups:
- name: application.rules
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{code=~"5.."}[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate detected"
description: "Error rate is {{ $value }} for {{ $labels.job }}"

- alert: HighResponseTime
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "High response time detected"
description: "95th percentile response time is {{ $value }}s for {{ $labels.job }}"

- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Pod is crash looping"
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} is crash looping"

- alert: HighMemoryUsage
expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage"
description: "Memory usage is {{ $value | humanizePercentage }} for {{ $labels.pod }}"

- alert: HighCPUUsage
expr: rate(container_cpu_usage_seconds_total[5m]) > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU usage"
description: "CPU usage is {{ $value | humanizePercentage }} for {{ $labels.pod }}"

应用监控代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// monitoring.js - 应用监控实现
const prometheus = require('prom-client');
const express = require('express');

class ApplicationMonitoring {
constructor() {
// 创建指标注册表
this.register = new prometheus.Registry();

// 添加默认指标
prometheus.collectDefaultMetrics({
register: this.register,
prefix: 'nodejs_'
});

this.setupCustomMetrics();
this.setupMiddleware();
}

setupCustomMetrics() {
// HTTP请求计数器
this.httpRequestsTotal = new prometheus.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code'],
registers: [this.register]
});

// HTTP请求持续时间
this.httpRequestDuration = new prometheus.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10],
registers: [this.register]
});

// 活跃连接数
this.activeConnections = new prometheus.Gauge({
name: 'active_connections',
help: 'Number of active connections',
registers: [this.register]
});

// 数据库连接池
this.dbConnectionPool = new prometheus.Gauge({
name: 'db_connection_pool_size',
help: 'Database connection pool size',
labelNames: ['pool_name', 'state'],
registers: [this.register]
});

// 业务指标
this.userRegistrations = new prometheus.Counter({
name: 'user_registrations_total',
help: 'Total number of user registrations',
registers: [this.register]
});

this.userLogins = new prometheus.Counter({
name: 'user_logins_total',
help: 'Total number of user logins',
labelNames: ['status'],
registers: [this.register]
});

this.ordersCreated = new prometheus.Counter({
name: 'orders_created_total',
help: 'Total number of orders created',
labelNames: ['status'],
registers: [this.register]
});

// 缓存指标
this.cacheOperations = new prometheus.Counter({
name: 'cache_operations_total',
help: 'Total number of cache operations',
labelNames: ['operation', 'result'],
registers: [this.register]
});

// 队列指标
this.queueSize = new prometheus.Gauge({
name: 'queue_size',
help: 'Current queue size',
labelNames: ['queue_name'],
registers: [this.register]
});

this.queueProcessingTime = new prometheus.Histogram({
name: 'queue_processing_duration_seconds',
help: 'Time spent processing queue items',
labelNames: ['queue_name', 'status'],
buckets: [0.1, 0.5, 1, 2, 5, 10, 30],
registers: [this.register]
});
}

setupMiddleware() {
this.middleware = (req, res, next) => {
const start = Date.now();

// 增加活跃连接数
this.activeConnections.inc();

// 监听响应结束事件
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
const route = req.route ? req.route.path : req.path;
const labels = {
method: req.method,
route: route,
status_code: res.statusCode
};

// 记录指标
this.httpRequestsTotal.inc(labels);
this.httpRequestDuration.observe(labels, duration);

// 减少活跃连接数
this.activeConnections.dec();
});

next();
};
}

// 业务指标记录方法
recordUserRegistration() {
this.userRegistrations.inc();
}

recordUserLogin(success = true) {
this.userLogins.inc({ status: success ? 'success' : 'failure' });
}

recordOrderCreation(status = 'success') {
this.ordersCreated.inc({ status });
}

recordCacheOperation(operation, result) {
this.cacheOperations.inc({ operation, result });
}

updateQueueSize(queueName, size) {
this.queueSize.set({ queue_name: queueName }, size);
}

recordQueueProcessing(queueName, status, duration) {
this.queueProcessingTime.observe({
queue_name: queueName,
status
}, duration);
}

updateDbConnectionPool(poolName, active, idle, total) {
this.dbConnectionPool.set({ pool_name: poolName, state: 'active' }, active);
this.dbConnectionPool.set({ pool_name: poolName, state: 'idle' }, idle);
this.dbConnectionPool.set({ pool_name: poolName, state: 'total' }, total);
}

// 健康检查端点
createHealthCheckHandler() {
return async (req, res) => {
const healthCheck = {
uptime: process.uptime(),
message: 'OK',
timestamp: new Date().toISOString(),
checks: {
database: await this.checkDatabase(),
redis: await this.checkRedis(),
external_api: await this.checkExternalAPI()
}
};

const isHealthy = Object.values(healthCheck.checks).every(check => check.status === 'healthy');

res.status(isHealthy ? 200 : 503).json(healthCheck);
};
}

// 指标端点
createMetricsHandler() {
return async (req, res) => {
res.set('Content-Type', this.register.contentType);
res.end(await this.register.metrics());
};
}

async checkDatabase() {
try {
// 实现数据库健康检查
// const result = await db.query('SELECT 1');
return { status: 'healthy', responseTime: '5ms' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}

async checkRedis() {
try {
// 实现Redis健康检查
// const result = await redis.ping();
return { status: 'healthy', responseTime: '2ms' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}

async checkExternalAPI() {
try {
// 实现外部API健康检查
return { status: 'healthy', responseTime: '150ms' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}

// 启动监控服务器
startMetricsServer(port = 9090) {
const app = express();

app.get('/health', this.createHealthCheckHandler());
app.get('/metrics', this.createMetricsHandler());

app.listen(port, () => {
console.log(`Metrics server started on port ${port}`);
});
}
}

module.exports = ApplicationMonitoring;

7. 日志管理

结构化日志实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// logger.js - 结构化日志
const winston = require('winston');
const { ElasticsearchTransport } = require('winston-elasticsearch');

class StructuredLogger {
constructor(config = {}) {
this.config = {
level: config.level || 'info',
service: config.service || 'unknown-service',
version: config.version || '1.0.0',
environment: config.environment || 'development',
...config
};

this.logger = this.createLogger();
}

createLogger() {
const formats = [
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json(),
winston.format.printf(info => {
return JSON.stringify({
timestamp: info.timestamp,
level: info.level,
message: info.message,
service: this.config.service,
version: this.config.version,
environment: this.config.environment,
traceId: info.traceId,
spanId: info.spanId,
userId: info.userId,
requestId: info.requestId,
...info.metadata
});
})
];

const transports = [
new winston.transports.Console({
format: winston.format.combine(...formats)
})
];

// 生产环境添加文件和Elasticsearch传输
if (this.config.environment === 'production') {
transports.push(
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
format: winston.format.combine(...formats)
}),
new winston.transports.File({
filename: 'logs/combined.log',
format: winston.format.combine(...formats)
})
);

if (this.config.elasticsearch) {
transports.push(
new ElasticsearchTransport({
level: 'info',
clientOpts: this.config.elasticsearch,
index: `logs-${this.config.service}`,
indexTemplate: {
name: `logs-${this.config.service}`,
body: {
index_patterns: [`logs-${this.config.service}-*`],
template: {
mappings: {
properties: {
'@timestamp': { type: 'date' },
level: { type: 'keyword' },
message: { type: 'text' },
service: { type: 'keyword' },
environment: { type: 'keyword' },
traceId: { type: 'keyword' },
userId: { type: 'keyword' }
}
}
}
}
}
})
);
}
}

return winston.createLogger({
level: this.config.level,
transports
});
}

// 创建带上下文的子日志器
child(context = {}) {
return {
debug: (message, metadata = {}) => this.debug(message, { ...context, ...metadata }),
info: (message, metadata = {}) => this.info(message, { ...context, ...metadata }),
warn: (message, metadata = {}) => this.warn(message, { ...context, ...metadata }),
error: (message, metadata = {}) => this.error(message, { ...context, ...metadata })
};
}

debug(message, metadata = {}) {
this.logger.debug(message, { metadata });
}

info(message, metadata = {}) {
this.logger.info(message, { metadata });
}

warn(message, metadata = {}) {
this.logger.warn(message, { metadata });
}

error(message, metadata = {}) {
this.logger.error(message, { metadata });
}

// HTTP请求日志中间件
createHttpMiddleware() {
return (req, res, next) => {
const start = Date.now();
const requestId = req.headers['x-request-id'] || this.generateRequestId();

// 添加请求ID到请求对象
req.requestId = requestId;
res.setHeader('X-Request-ID', requestId);

// 记录请求开始
this.info('HTTP request started', {
requestId,
method: req.method,
url: req.url,
userAgent: req.get('User-Agent'),
ip: req.ip,
userId: req.user?.id
});

// 监听响应结束
res.on('finish', () => {
const duration = Date.now() - start;
const level = res.statusCode >= 400 ? 'warn' : 'info';

this[level]('HTTP request completed', {
requestId,
method: req.method,
url: req.url,
statusCode: res.statusCode,
duration,
userId: req.user?.id
});
});

next();
};
}

// 错误处理中间件
createErrorMiddleware() {
return (error, req, res, next) => {
this.error('Unhandled error', {
requestId: req.requestId,
error: {
name: error.name,
message: error.message,
stack: error.stack
},
method: req.method,
url: req.url,
userId: req.user?.id
});

next(error);
};
}

generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}

module.exports = StructuredLogger;

8. 安全最佳实践

容器安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 安全的Dockerfile示例
FROM node:18-alpine AS base

# 安装安全更新
RUN apk update && apk upgrade && \
apk add --no-cache dumb-init && \
rm -rf /var/cache/apk/*

# 创建非特权用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001 -G nodejs

# 构建阶段
FROM base AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build

# 生产阶段
FROM base AS production
WORKDIR /app

# 复制文件并设置权限
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json

# 安全配置
ENV NODE_ENV=production
ENV NPM_CONFIG_LOGLEVEL=warn
USER nextjs

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1

# 使用dumb-init
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]

Pod安全策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# pod-security-policy.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
readOnlyRootFilesystem: true
seccompProfile:
type: 'RuntimeDefault'

---
apiVersion: v1
kind: ServiceAccount
metadata:
name: restricted-sa
namespace: production

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: psp-user
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['restricted-psp']

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: psp-binding
namespace: production
roleRef:
kind: Role
name: psp-user
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: restricted-sa
namespace: production

9. 性能优化

应用性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// performance-optimizer.js
const cluster = require('cluster');
const os = require('os');
const compression = require('compression');
const helmet = require('helmet');

class PerformanceOptimizer {
constructor(app) {
this.app = app;
this.setupCluster();
this.setupMiddleware();
this.setupCaching();
this.setupConnectionPooling();
}

setupCluster() {
if (cluster.isMaster && process.env.NODE_ENV === 'production') {
const numCPUs = os.cpus().length;
console.log(`Master ${process.pid} is running`);

// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}

cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork();
});
}
}

setupMiddleware() {
// 安全头
this.app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"]
}
}
}));

// 压缩
this.app.use(compression({
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
},
level: 6,
threshold: 1024
}));

// 静态文件缓存
this.app.use('/static', express.static('public', {
maxAge: '1y',
etag: true,
lastModified: true,
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'no-cache');
}
}
}));
}

setupCaching() {
const NodeCache = require('node-cache');
this.cache = new NodeCache({
stdTTL: 600, // 10分钟
checkperiod: 120, // 2分钟检查过期
useClones: false
});

// 缓存中间件
this.cacheMiddleware = (ttl = 600) => {
return (req, res, next) => {
const key = `cache:${req.method}:${req.originalUrl}`;
const cached = this.cache.get(key);

if (cached) {
return res.json(cached);
}

// 重写res.json以缓存响应
const originalJson = res.json;
res.json = (data) => {
this.cache.set(key, data, ttl);
return originalJson.call(res, data);
};

next();
};
};
}

setupConnectionPooling() {
// 数据库连接池配置
this.dbPoolConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
max: 20, // 最大连接数
min: 5, // 最小连接数
acquire: 30000, // 获取连接超时
idle: 10000, // 空闲超时
evict: 1000, // 清理间隔
handleDisconnects: true,
reconnectTries: 3
};

// Redis连接池
this.redisPoolConfig = {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
db: 0,
maxRetriesPerRequest: 3,
retryDelayOnFailover: 100,
enableReadyCheck: false,
maxLoadingTimeout: 5000,
lazyConnect: true,
family: 4,
keepAlive: true,
connectTimeout: 10000,
commandTimeout: 5000
};
}

// 内存使用监控
monitorMemoryUsage() {
setInterval(() => {
const usage = process.memoryUsage();
const used = Math.round(usage.heapUsed / 1024 / 1024 * 100) / 100;
const total = Math.round(usage.heapTotal / 1024 / 1024 * 100) / 100;

console.log(`Memory usage: ${used}MB / ${total}MB`);

// 内存使用超过阈值时触发垃圾回收
if (used > 500) { // 500MB
if (global.gc) {
global.gc();
console.log('Garbage collection triggered');
}
}
}, 30000); // 30秒检查一次
}

// 请求限流
createRateLimiter() {
const rateLimit = require('express-rate-limit');

return rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 100次请求
message: {
error: 'Too many requests from this IP',
retryAfter: '15 minutes'
},
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: 'Rate limit exceeded',
retryAfter: Math.round(req.rateLimit.resetTime / 1000)
});
}
});
}

// 响应时间优化
optimizeResponseTime() {
this.app.use((req, res, next) => {
const start = Date.now();

res.on('finish', () => {
const duration = Date.now() - start;
res.setHeader('X-Response-Time', `${duration}ms`);

// 记录慢请求
if (duration > 1000) {
console.warn(`Slow request: ${req.method} ${req.url} - ${duration}ms`);
}
});

next();
});
}
}

module.exports = PerformanceOptimizer;

10. 总结与最佳实践

云原生架构设计原则

  1. 十二要素应用

    • 代码库:一个代码库,多个部署
    • 依赖:显式声明和隔离依赖
    • 配置:在环境中存储配置
    • 后端服务:把后端服务当作附加资源
    • 构建、发布、运行:严格分离构建和运行
    • 进程:以一个或多个无状态进程运行应用
    • 端口绑定:通过端口绑定提供服务
    • 并发:通过进程模型进行扩展
    • 易处理:快速启动和优雅终止
    • 开发环境与线上环境等价
    • 日志:把日志当作事件流
    • 管理进程:后台管理任务当作一次性进程运行
  2. 微服务设计原则

    • 单一职责:每个服务只负责一个业务功能
    • 自治性:服务独立开发、部署和扩展
    • 去中心化:避免单点故障和性能瓶颈
    • 容错性:设计时考虑故障场景
    • 可观测性:提供充分的监控和日志
  3. 容器化最佳实践

    • 使用多阶段构建减小镜像大小
    • 运行非特权用户
    • 使用健康检查
    • 设置资源限制
    • 实现优雅关闭
  4. Kubernetes部署策略

    • 使用命名空间隔离环境
    • 配置资源请求和限制
    • 实现水平和垂直自动扩缩容
    • 使用滚动更新和金丝雀部署
    • 配置网络策略和安全策略
  5. CI/CD流水线

    • 自动化测试和质量检查
    • 容器镜像安全扫描
    • 基础设施即代码
    • GitOps部署模式
    • 渐进式交付
  6. 监控和可观测性

    • 三大支柱:指标、日志、链路追踪
    • 业务指标和技术指标并重
    • 主动监控和告警
    • 分布式链路追踪
    • 性能基准测试

未来发展方向

  1. Serverless架构

    • 函数即服务(FaaS)
    • 事件驱动架构
    • 按需计费模式
  2. 边缘计算

    • CDN集成
    • 边缘函数
    • 就近处理
  3. AI/ML集成

    • 智能运维(AIOps)
    • 自动化决策
    • 预测性扩缩容
  4. 安全左移

    • DevSecOps
    • 安全即代码
    • 零信任架构

云原生架构为现代应用提供了强大的基础设施和开发模式,通过容器化、微服务、自动化等技术,实现了应用的快速交付、弹性扩展和高可用性。掌握这些核心技术和最佳实践,将帮助开发团队构建更加健壮、可扩展的云原生应用。