第 7 章:微服务入门
学习目标
- 理解单体架构的痛点和微服务的价值
- 掌握微服务的核心特征
- 区分微服务 vs SOA vs Serverless
- 识别"为了拆而拆"的常见坑
一、单体架构的痛点
text
巨型单体(Monolith)
├── 用户模块
├── 商品模块
├── 订单模块
├── 支付模块
└── 库存模块
所有功能 → 一个 WAR/JAR → 一个 Tomcat/JVMjava
// 单体时代的代码结构
com.example.ecommerce
├── controller
├── service
└── dao
// 所有人提交同一个 Git 仓库,改一行代码全团队等部署单体三大痛点:
- 编译慢:代码膨胀到 100 万行,改 5 行代码编译 10 分钟
- 部署慢:一个 bug 修复也要全量发布,凌晨 3 点才能上线
- 扩展难:商品模块要扩 10 倍,只能整个应用扩,浪费资源
⚠️ 坑 1:"等拆成微服务,这些问题就解决了" — 拆完数据库还是同一台,事务更乱,反而更糟。先优化单体,瓶颈明确再拆。
二、微服务定义
Martin Fowler 2014 年提出:
一组小型服务,每个服务独立部署,围绕业务能力组织,去中心化,轻量级通信。
text
微服务架构
├── 用户服务(Spring Boot)
├── 商品服务(Spring Boot)
├── 订单服务(Spring Boot)
└── 支付服务(Spring Boot)
每个服务 = 独立进程 + 独立部署 + 独立数据库java
// 订单服务调用支付服务(远程调用)
@Service
public class OrderService {
@Resourceprivate PaymentClient paymentClient; // Feign 客户端
public void pay(OrderId orderId) {
Order order = orderRepository.findById(orderId);
PaymentResult result = paymentClient.pay(order.id(), order.amount());
if (result.success()) {
order.markPaid();
}
}
}三、微服务的核心特征
| 特征 | 说明 |
|---|---|
| 独立部署 | 一个服务一个进程,独立扩缩容 |
| 围绕业务能力 | 按业务边界切分,不是按技术层 |
| 去中心化 | 数据去中心(库),治理去中心(技术栈) |
| 轻量通信 | HTTP/REST 或 gRPC,不用 ESB |
| 故障隔离 | 一个服务挂掉不影响其他 |
| 数据隔离 | 一个服务一个数据库 |
java
// 数据隔离:每个服务独立数据库
public class OrderApplication {
@Bean
public DataSource orderDataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://order-db:3306/order_db")
.username("order_user")
.password("xxx")
.build();
}
}⚠️ 坑 2:"每个服务一个数据库" ≠ "每张表一个数据库"。服务边界 = 数据库边界,不要让订单服务和库存服务共享一个 MySQL 实例。
四、微服务 vs SOA vs Serverless
| 维度 | 单体 | SOA | 微服务 | Serverless |
|---|---|---|---|---|
| 颗粒度 | 整个应用 | 业务模块 | 业务能力 | 函数 |
| 通信 | 内部调用 | ESB | HTTP/gRPC | 事件 |
| 部署 | 一起 | 多个 | 各自独立 | 各自独立 |
| 适用 | 小团队 | 大企业转型 | 互联网 | 流量波动大 |
java
// Serverless 示例:AWS Lambda
public class OrderPlacedHandler implements RequestHandler<OrderEvent, String> {
@Override
public String handleRequest(OrderEvent event, Context context) {
// 发送邮件
emailService.send(event.getBuyerEmail(), "订单已创建");
return "ok";
}
}五、什么时候应该拆微服务?
text
✅ 适合拆
├── 团队 50+ 人,代码冲突严重
├── 业务复杂,需要频繁独立发布
├── 部分模块扩展需求(秒杀、推荐)
└── 多语言栈(Go / Python / Java)
❌ 暂不建议拆
├── 团队 < 10 人
├── 业务早期,需求频繁变
├── 一致性要求极高(金融核心)
└── 没有 DevOps 能力⚠️ 坑 3:创业公司 5 人团队上来就拆 10 个微服务,光治理就耗光精力。先单体 + 模块化,业务稳定再拆。
六、微服务的代价
text
分布式带来的复杂度:
├── 服务发现(几十个服务怎么找)
├── 配置管理(配置分散在各服务)
├── 链路追踪(请求跨 5 个服务怎么追)
├── 分布式事务(下单 + 扣库存怎么一致)
├── 熔断降级(下游挂了怎么处理)
├── API 网关(统一入口)
└── 监控告警(几十个服务的健康度)java
// 这些问题累加成本很高
@Component
public class DistributedTracingConfig {
@Bean
public Tracer tracer() {
return new ZipkinTracer();
}
}没有 3-5 人的 SRE 团队,不要贸然上微服务。
本章小结
| 维度 | 单体 | 微服务 |
|---|---|---|
| 部署 | 一起 | 独立 |
| 数据库 | 共享 | 各自独立 |
| 通信 | 内部调用 | HTTP/gRPC |
| 故障 | 全局 | 隔离 |
| 复杂度 | 低 | 高 |
| 适用 | 早期 | 成熟 |
动手练习
- 单体切分:把一个单体电商项目拆成 user/product/order/payment 四个 Spring Boot 应用
- 数据库隔离:为每个服务申请独立数据库,演示跨服务调用时不能直接连对方库
- REST 调用:用 OpenFeign 写一个
OrderClient调用支付服务的/api/payments - 压测对比:对一个服务压测,观察独立部署 vs 整体部署的扩容差异
下一章:第 8 章:微服务拆分 →