微服务 vs 单体:中小团队的务实选择
我们团队 6 个人,去年把单体拆成了微服务,今年又合回去了。这段经历值得聊聊。
为什么拆
2023 年,我们的单体应用遇到了问题:
- 代码仓库太大,clone 要 5 分钟
- 每次部署整个应用,一个小改动要等 10 分钟
- 数据库单表破千万,查询越来越慢
- 团队变大了,不同小组互相踩代码
怎么拆的
我们按业务域拆成了 5 个服务:
CODE
用户服务 (3002) ─┐
订单服务 (3003) ─┼── API Gateway (3001) ── 前端
商品服务 (3004) ─┤
支付服务 (3005) ─┤
通知服务 (3006) ─┘技术栈:
- 服务间通信:gRPC
- 消息队列:RabbitMQ
- 服务发现:Consul
- 链路追踪:Jaeger
遇到了什么
问题 1:分布式事务
PYTHON
# 下单需要:扣库存 + 创建订单 + 扣款
# 单体里一个事务搞定,微服务里变成分布式事务
def create_order():
try:
inventory_service.deduct(product_id, quantity)
order = order_service.create(user_id, product_id)
payment_service.charge(user_id, amount)
except Exception:
# 补偿逻辑...非常复杂
inventory_service.restore(product_id, quantity)
raise问题 2:调试地狱
一个请求经过 4 个服务,出问题要看 4 个日志文件。
问题 3:运维成本
5 个服务 = 5 个 CI/CD 流水线、5 个部署、5 个监控。
为什么又合回去了
我们的日活只有 2 万,5 个服务完全是过度设计。
合回去的方案:模块化单体
CODE
src/
├── modules/
│ ├── user/ # 用户模块
│ ├── order/ # 订单模块
│ ├── product/ # 商品模块
│ └── payment/ # 支付模块
├── shared/ # 共享代码
└── main.ts # 统一入口TYPESCRIPT
// 模块间通过接口通信,不直接依赖
interface IUserService {
getUser(id: string): Promise<User>
}
// 未来如果需要拆分,改接口实现即可我的建议
| 条件 | 推荐 |
|------|------|
| 团队 < 10 人 | 模块化单体 |
| 日活 < 10 万 | 模块化单体 |
| 单一业务线 | 模块化单体 |
| 多团队 + 独立部署需求 | 微服务 |
| 日活 > 100 万 | 微服务 |
微服务是组织架构的映射,不是技术升级。 团队没有微服务的管理能力,就别碰微服务。
读者评论 4