两种架构

单体(Monolith):所有功能在同一个代码库、同一个部署单元中。模块之间通过函数调用通信。

微服务(Microservices):拆分成多个独立的服务,各自独立开发、部署、扩展。服务之间通过网络通信(HTTP/RPC 或消息队列)。

微服务的真实收益

一、独立部署与发布。 改一个模块不需要重新部署整个系统,发布频率可以更高,风险更小。

二、技术栈灵活。 不同服务可以用不同的语言、数据库——因为需要,也因为可以。

三、独立扩展。 只有某个服务压力大时,只扩容它,而不是整个应用。

四、故障隔离。 一个服务崩溃,理论上不该拖垮整个系统(前提是有熔断、降级设计)。

五、团队自治。 小团队负责自己的服务,决策链条短。

微服务的真实成本

一、分布式系统的复杂性。 这是最大的代价:

  • 网络调用会失败、会超时、会重试,必须处理;
  • 分布式事务极其复杂,多数情况下只能通过最终一致性来规避;
  • 调试困难——一个请求跨越多个服务,定位问题需要分布式追踪;
  • 数据一致性、幂等性、消息顺序等问题接踵而来。

二、运维负担。 服务数量从 1 变成几十上百,需要:

  • 服务发现与注册;
  • 配置中心;
  • 集中式日志与监控;
  • 链路追踪;
  • 容器编排;
  • CI/CD 流水线。

三、网络开销。 进程内函数调用是纳秒级,跨服务网络调用是毫秒级,差了几个数量级。

四、团队协作成本。 服务边界划分不当,会导致大量跨团队协调,反而降低效率。

康威定律

系统的架构,会受到产生它的组织的沟通结构的制约。

这是选择架构时最该记住的一条:架构要匹配组织结构。

如果一个团队只有 5 个人,拆成 20 个微服务是灾难;如果公司有几百个开发者共享一个代码库,单体也会成为瓶颈。

微服务的主要收益,其实来自让团队能够独立工作,而不是技术本身的先进性。

一个务实的路径

从单体开始,按需拆分。

Martin Fowler 提出的"单体优先"建议,被很多团队验证过:

  1. 先用单体把业务跑起来,验证需求;
  2. 当某个模块确实成为瓶颈(需要独立扩展、独立发布、或团队边界清晰)时,再拆出去;
  3. 拆分时,优先沿着业务边界而非技术分层来拆。

过早微服务化的风险在于:你还不知道正确的服务边界在哪里。而错误的边界比单体更糟糕——修改一个功能要跨多个服务协调,成本极高。

折中方案:模块化单体

在单体内部保持清晰的模块边界(通过代码组织、依赖规则、接口约束),既获得单体的简单性,又保留了未来拆分的可能。

这对大多数中小型项目,可能是最优选择。

说明:本文为软件架构实践的分析。