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个,基础设施管理成为痛点:可以考虑服务网格。但要做好学习成本的准备。

记住一句话:

架构演进不是赶时髦,而是解决实际问题。如果你的单体还没遇到瓶颈,就别急着拆。我见过太多「为了微服务而微服务」的项目,最后把自己搞得很痛苦。

好了,这一章我们聊了四种架构的演进脉络。下一章我会深入讲微服务的拆分原则——到底怎么拆才合理?到时候我会分享一些实战中的血泪教训。