2. 微服务架构演进:从单体到服务网格
聊到微服务架构,很多人一上来就谈容器、谈Kubernetes。但我个人习惯,先带大家看看这条路是怎么走过来的。说白了,没有前面的单体架构和SOA,就不会有今天的微服务和服务网格。
我在2014年接手过一个电商系统,当时就是典型的单体架构。代码量大概50万行,每次发布都要停机半小时。嗯,那滋味真不好受。今天我们就从那个年代开始聊起。
2.1 单体架构:一切从简
单体架构,就是把所有功能都打包在一个进程里。前端、后端、数据库访问、业务逻辑,全揉在一起。
核心特征:
- 所有代码在一个工程里
- 部署时打成一个包(WAR/JAR)
- 共享一个数据库实例
- 团队协作靠代码分支管理
你想想看,这种架构有什么好处?开发简单啊!我刚入行那会儿,一个项目两三个人,从数据库设计到前端页面,全包了。调试也方便,IDE里直接跑起来就能看效果。
但问题也很明显。我记得有一次,只是改了个支付页面的文案,结果因为依赖关系,把整个订单模块都重新编译了一遍。更别提扩容了——你明明只是搜索模块压力大,却要把整个应用都复制一份。
我曾经踩过的坑:
有一次线上故障,原因是某个同事在公共工具类里改了一个静态变量的初始化顺序。结果影响到了十几个业务模块。排查了整整一个下午。从那以后,我对单体架构里的「共享」二字就特别敏感。
2.2 SOA架构:服务化的第一次尝试
SOA(面向服务架构)的出现,其实是被逼出来的。业务越来越复杂,单体扛不住了。大家开始想:能不能把系统拆成几个独立的服务?
SOA的核心思路是:
- 服务通过ESB(企业服务总线)通信
- 服务之间用SOAP/XML协议
- 强调服务复用和治理
我在2016年参与过一个SOA改造项目。当时我们用了Oracle的OSB(Oracle Service Bus)。说实话,ESB确实解决了服务间通信的问题,但也带来了新的麻烦。
个人经验:
ESB容易变成单点瓶颈。我们当时所有服务都经过ESB,结果ESB一挂,全系统瘫痪。而且XML解析的性能开销,在高并发场景下特别明显。说白了,SOA太重了。
SOA和单体架构的对比,我整理了一张表:
| 维度 | 单体架构 | SOA架构 |
|---|---|---|
| 服务粒度 | 粗粒度(整个应用) | 中粒度(业务模块) |
| 通信方式 | 进程内调用 | ESB/XML |
| 部署方式 | 单点部署 | 分布式部署 |
| 治理能力 | 弱 | 强(但复杂) |
| 典型技术 | Tomcat + WAR | Oracle OSB、IBM WebSphere |
2.3 微服务架构:轻量化的服务拆分
微服务架构,你可以理解为SOA的「瘦身版」。它去掉了笨重的ESB,改用轻量级的HTTP/REST或gRPC通信。
核心原则就几条:
- 每个服务专注做一件事
- 服务独立部署、独立扩展
- 去中心化治理
- 自动化运维(CI/CD)
我2018年开始全面转向微服务。当时选型用了Spring Cloud + Docker。说实话,刚开始确实爽——每个服务都很小,改起来快,部署也快。
微服务带来的好处:
- 技术栈可以异构(Java + Go + Node.js混用)
- 故障隔离(一个服务挂了不影响其他)
- 独立扩缩容(哪个模块压力大就扩哪个)
- 团队自治(每个团队负责自己的服务)
但微服务也不是银弹。我遇到过最头疼的问题就是分布式事务。以前单体里一个本地事务就搞定的事,拆成微服务后,得用Saga模式或者TCC。调试起来特别麻烦。
避坑指南:
我曾经在一个项目里,把用户服务拆得太细了——登录一个服务,注册一个服务,个人信息一个服务,地址管理又一个服务。结果服务间调用链特别长,一个简单的用户注册流程,要调5个服务。后来我学乖了,服务拆分要适度,别为了拆而拆。
2.4 服务网格架构:把基础设施下沉
服务网格(Service Mesh)是最近几年火起来的。它的思路很巧妙:把服务间通信的逻辑从业务代码里抽出来,放到一个独立的代理层里。
典型的实现是Istio + Envoy。每个服务旁边都跑一个Sidecar代理,负责流量管理、服务发现、负载均衡、熔断限流这些事。
// 传统微服务:业务代码里要写熔断逻辑
@HystrixCommand(fallbackMethod = "fallback")
public Order getOrder(Long orderId) {
return orderServiceClient.getOrder(orderId);
}
// 服务网格:熔断逻辑在Sidecar里配置
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: order-service
spec:
host: order-service
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 100
maxRequestsPerConnection: 10
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
你看,业务代码里不用再写那些基础设施相关的逻辑了。开发人员只需要关注业务,网络通信的事交给Sidecar。
我的感受:
服务网格最大的价值,是把「非功能性需求」和「业务代码」解耦了。以前每个微服务都要集成Hystrix、Ribbon这些库,升级一次要改所有服务。现在只需要改Sidecar的配置就行。我去年帮一个团队迁移到Istio,光熔断配置就省了上千行代码。
四种架构的演进关系,我用一个表格总结:
| 架构模式 | 核心思想 | 通信方式 | 运维复杂度 | 适用场景 |
|---|---|---|---|---|
| 单体架构 | 一切打包 | 进程内调用 | 低 | 小团队、简单业务 |
| SOA架构 | 服务化+ESB | ESB/XML | 高 | 大型企业、系统集成 |
| 微服务架构 | 轻量服务拆分 | HTTP/gRPC | 中 | 互联网业务、快速迭代 |
| 服务网格 | 基础设施下沉 | Sidecar代理 | 中高 | 大规模微服务、云原生 |
2.5 如何选择?我的建议
很多同学问我:现在是不是直接上服务网格?我的回答是:看情况。
- 团队小于10人,业务简单:单体架构完全够用。别为了技术而技术。
- 业务中等规模,需要快速迭代:微服务架构是主流选择。配合Docker和Kubernetes,效果不错。
- 服务数量超过50个,基础设施管理成为痛点:可以考虑服务网格。但要做好学习成本的准备。
记住一句话:
架构演进不是赶时髦,而是解决实际问题。如果你的单体还没遇到瓶颈,就别急着拆。我见过太多「为了微服务而微服务」的项目,最后把自己搞得很痛苦。
好了,这一章我们聊了四种架构的演进脉络。下一章我会深入讲微服务的拆分原则——到底怎么拆才合理?到时候我会分享一些实战中的血泪教训。