微服务架构入门与实践指南
📅 2024年1月17日
⏱️ 阅读时间: 16分钟
微服务核心概念
微服务 vs 单体架构
// 单体架构示例
// 一个大型应用包含所有功能模块
app/
├── controllers/
├── models/
├── views/
├── services/
└── utils/
// 微服务架构示例
// 多个独立的小服务
services/
├── user-service/ # 用户服务
├── product-service/ # 产品服务
├── order-service/ # 订单服务
├── payment-service/ # 支付服务
└── notification-service/# 通知服务
服务拆分原则
- 单一职责:每个服务只负责一个业务领域
- 独立部署:服务可以独立部署和扩展
- 技术异构:不同服务可以使用不同技术栈
- 数据自治:每个服务有自己的数据库
- 轻量级通信:通过API进行通信
微服务通信模式
同步通信(REST/gRPC)
// REST API调用
const axios = require('axios');
class OrderService {
async createOrder(userId, products) {
// 调用用户服务
const user = await axios.get(`http://user-service/users/${userId}`);
// 调用产品服务验证库存
const inventoryCheck = await axios.post(
'http://product-service/check-inventory',
{ products }
);
// 创建订单
const order = await axios.post('http://order-service/orders', {
userId,
products,
total: inventoryCheck.data.total
});
return order.data;
}
}
// gRPC示例
// 定义proto文件
syntax = "proto3";
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
string id = 1;
}
message UserResponse {
string id = 1;
string name = 2;
string email = 3;
}
异步通信(消息队列)
// 使用RabbitMQ进行异步通信
const amqp = require('amqplib');
class NotificationService {
async start() {
// 连接消息队列
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
// 声明队列
await channel.assertQueue('order.created', { durable: true });
await channel.assertQueue('payment.processed', { durable: true });
// 消费消息
channel.consume('order.created', async (msg) => {
const order = JSON.parse(msg.content.toString());
await this.sendOrderConfirmation(order);
channel.ack(msg);
});
channel.consume('payment.processed', async (msg) => {
const payment = JSON.parse(msg.content.toString());
await this.sendPaymentReceipt(payment);
channel.ack(msg);
});
}
async sendOrderConfirmation(order) {
// 发送订单确认邮件
console.log(`发送订单确认邮件给用户 ${order.userId}`);
}
async sendPaymentReceipt(payment) {
// 发送支付收据
console.log(`发送支付收据给用户 ${payment.userId}`);
}
}
// 生产者发送消息
class OrderService {
async createOrder(orderData) {
// 创建订单逻辑...
const order = await this.saveOrder(orderData);
// 发布订单创建事件
const channel = await this.getChannel();
channel.sendToQueue('order.created',
Buffer.from(JSON.stringify(order)),
{ persistent: true }
);
return order;
}
}
服务发现与配置
使用Consul进行服务发现
// 服务注册
const consul = require('consul')();
class UserService {
constructor() {
this.serviceId = `user-service-${process.pid}`;
}
async registerService() {
await consul.agent.service.register({
id: this.serviceId,
name: 'user-service',
address: 'localhost',
port: 3001,
check: {
http: 'http://localhost:3001/health',
interval: '10s',
timeout: '5s'
}
});
}
async deregisterService() {
await consul.agent.service.deregister(this.serviceId);
}
}
// 服务发现
class ServiceDiscovery {
async discoverService(serviceName) {
const services = await consul.agent.service.list();
const service = Object.values(services)
.find(s => s.Service === serviceName);
if (!service) {
throw new Error(`服务 ${serviceName} 未找到`);
}
return `http://${service.Address}:${service.Port}`;
}
}
配置管理
// 使用环境变量和配置中心
// .env文件
DATABASE_URL=postgresql://user:pass@localhost:5432/db
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key
// 配置类
class Config {
constructor() {
this.databaseUrl = process.env.DATABASE_URL;
this.redisUrl = process.env.REDIS_URL;
this.jwtSecret = process.env.JWT_SECRET;
this.servicePort = parseInt(process.env.PORT) || 3000;
}
// 从配置中心获取配置
async loadFromConfigCenter() {
const response = await fetch('http://config-center/config/user-service');
const config = await response.json();
Object.assign(this, config);
}
}
// Docker Compose配置
version: '3.8'
services:
config-center:
image: hashicorp/consul:latest
ports:
- "8500:8500"
user-service:
build: ./user-service
environment:
- CONSUL_HTTP_ADDR=config-center:8500
depends_on:
- config-center
部署和监控
Docker化部署
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# docker-compose.yml
version: '3.8'
services:
user-service:
build: ./user-service
ports:
- "3001:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/users
depends_on:
- db
- redis
product-service:
build: ./product-service
ports:
- "3002:3000"
api-gateway:
build: ./api-gateway
ports:
- "80:3000"
depends_on:
- user-service
- product-service
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: pass
redis:
image: redis:alpine
监控和日志
// 集成Prometheus监控
const prometheus = require('prom-client');
// 创建指标
const httpRequestDurationMicroseconds = new prometheus.Histogram({
name: 'http_request_duration_ms',
help: 'HTTP请求持续时间(毫秒)',
labelNames: ['method', 'route', 'code'],
buckets: [50, 100, 200, 300, 400, 500, 1000]
});
// 中间件记录指标
app.use((req, res, next) => {
const end = httpRequestDurationMicroseconds.startTimer();
res.on('finish', () => {
end({
method: req.method,
route: req.route?.path || req.path,
code: res.statusCode
});
});
next();
});
// 暴露metrics端点
app.get('/metrics', async (req, res) => {
res.set('Content-Type', prometheus.register.contentType);
res.end(await prometheus.register.metrics());
});
// 集中式日志
const winston = require('winston');
const { ElasticsearchTransport } = require('winston-elasticsearch');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
new ElasticsearchTransport({
level: 'info',
clientOpts: { node: 'http://elasticsearch:9200' }
})
]
});
// 使用日志
logger.info('用户服务启动', { port: 3001 });
logger.error('数据库连接失败', { error: err.message });
微服务
架构设计
分布式系统
云原生