后端架构实战(四):微服务的"分布式税"——你准备好买单了吗

写在前面

前三篇我一直在"劝退"过早微服务化,不是反对微服务,是想让你想清楚再拆。这一篇就把账算明白:拆成微服务之后,你到底要为哪些隐性成本买单

我把这些成本叫做**“分布式税”**——单体里免费的东西,到了分布式环境,每一项都要你自己花人、花钱、花时间重新建起来。


一、什么叫"分布式税"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
单体里(进程内)免费的能力:

  - 函数调用    = 直接 new、直接调,纳秒级
  - 强一致性    = 一个数据库事务搞定
  - 配置        = 读本地配置文件
  - 日志        = 写同一个文件
  - 鉴权        = 一个进程内的中间件
  - 故障传播    = 进程挂了,全挂(简单粗暴)

微服务里(跨网络)每一项都要重新建:

  - 函数调用 → 网络调用(毫秒级、会超时、会丢包)
  - 强一致   → 分布式事务(Saga / TCC / 最终一致)
  - 配置     → 配置中心(集中下发、动态刷新)
  - 日志     → 日志聚合(收集到统一存储)
  - 鉴权     → 每个服务都要验 token
  - 故障     → 一个挂了,可能雪崩倒一片

  这些"重建",就是分布式税。

二、第一笔税:网络根本不可靠

这是分布式系统一切痛苦的根源。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
进程内调用 vs 网络调用:

  进程内调用:
    ✓ 几乎不会失败(除非进程崩)
    ✓ 纳秒~微秒级
    ✓ 没有序列化开销

  网络调用:
    ✗ 会超时(对方慢、网络抖动)
    ✗ 会丢包、会重试、会乱序
    ✗ 毫秒级起步,还要序列化
    ✗ "超时"最可怕——不知道对方到底执行了没有

  八大谬误(Peter Deutsch):
    1. 网络是可靠的          ❌
    2. 延迟为零              ❌
    3. 带宽是无限的           ❌
    4. 网络是安全的           ❌
    5. 拓扑不会变化           ❌
    6. 只有一个管理员         ❌
    7. 传输成本为零           ❌
    8. 网络是同构的           ❌

代价:每一次跨服务调用,都要处理重试、超时、幂等、降级。单体里一个 try-catch 搞定的,微服务里是一整套弹性策略。

网络为什么不可靠、CAP 为什么成立——我在《分布式系统学习笔记(一):CAP 与一致性》里讲过底子。这里只说工程后果。


三、第二笔税:服务发现与配置

单体里,所有代码在一个进程,互相调函数即可。微服务里,“找谁"和"用什么配置"成了问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
单体:函数地址 = 编译期固定
微服务:服务实例的 IP/端口是动态的(容器漂移、弹性扩缩)

  必须自建的能力:
    - 服务注册与发现(谁在线、在哪)
      常见:Consul / Nacos / etcd / K8s Service / Eureka
    - 配置中心(配置不再散落各服务)
      常见:Nacos / Apollo / Consul KV / K8s ConfigMap
    - 动态刷新(改配置不重启)

  这些都是单体里"不存在"的基础设施。

四、第三笔税:数据一致性

这是最重的一笔税,下一篇会专门展开,这里先列账:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
单体:一个事务保证 ACID
微服务:每个服务一个库,跨库没有 ACID

  你必须自建:
    - 分布式事务方案(Saga、TCC、Outbox 模式)
    - 最终一致性补偿机制
    - 幂等性保证(重试导致的重复执行)
    - 对账机制(数据不一致时的人工/自动核对)

  详见我写的《分布式系统学习笔记(四):分布式事务》。
  本系列第五篇会讲它怎么在数据架构上落地。

五、第四笔税:可观测性

单体里,一个请求的处理在一个进程内,看一个日志文件就懂了。微服务里,一个请求要经过 5 个服务,出问题你怎么定位?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
必须自建"微服务的神经系统":

  - 链路追踪(Trace)
    给每个请求一个 traceId,跨服务透传
    常见:OpenTelemetry / Jaeger / Zipkin / SkyWalking

  - 指标监控(Metrics)
    每个服务的 QPS、延迟、错误率
    常见:Prometheus + Grafana

  - 日志聚合(Logs)
    所有服务的日志收到一处,按 traceId 串联
    常见:ELK / Loki

  没有这三件套,微服务一旦出问题 = 黑盒,只能玄学排查。
  第七篇会专门讲可观测性。

六、第五笔税:可靠性与弹性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
单体里:一个函数失败 → 抛异常,调用方决定怎么办
微服务里:一个服务失败 → 故障会沿调用链放大,可能雪崩

  必须自建:
    - 超时(Timeout)—— 别傻等
    - 重试(Retry)—— 配合幂等
    - 熔断(Circuit Breaker)—— 别打已经挂的服务
    - 限流(Rate Limit)—— 别被流量压垮
    - 降级(Fallback)—— 给个兜底响应
    - 舱壁隔离(Bulkhead)—— 别让一个慢调用拖垮线程池

  .NET 生态:Polly(这套东西几乎成了标配)
  本系列第八篇落地时会用上。
1
2
3
4
5
雪崩示意:
  服务 A 依赖 B,B 依赖 C
  C 慢了 → B 的线程被占满 → B 也慢 → A 的线程被占满 → A 也挂
  一个底层小故障,逐层放大,拖垮整条链路。
  熔断 + 舱壁就是用来切断这种放大效应的。

七、第六笔税:运维与部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
单体运维:1 个应用 × N 台机器
微服务运维:M 个服务 × N 个实例 × 动态变化

  - 需要容器化(Docker)+ 编排(K8s)
    见我写的 Docker / K8s 系列
  - 需要 CI/CD(每个服务独立构建、独立发布)
  - 需要版本兼容(新老接口并存期)
  - 需要 API 网关(统一入口、鉴权、限流)
  - 需要 DevOps 能力(SRE 文化)

  团队没有这些能力,上微服务 = 上灾难。

八、账单汇总:值得吗

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
拆成微服务,你要新增的基础设施清单:

  □ 服务注册发现      □ 配置中心
  □ API 网关          □ 分布式事务/一致性
  □ 链路追踪          □ 指标监控
  □ 日志聚合          □ 熔断/限流/重试(Polly)
  □ 容器编排(K8s)   □ CI/CD 流水线
  □ 幂等 + 对账       □ 版本兼容策略

  收益(只有规模到了才兑现):
    ✓ 独立部署、独立扩容、技术栈解耦、故障隔离、团队解耦

  判断标准:
    规模/团队/解耦需求 带来的收益 > 上面这份税单 → 拆
    否则 → 老老实实模块化单体

    这就是第一篇说的"权衡"。

九、小结

  • 分布式税:单体里免费的能力,微服务里每一项都要自建
  • 网络不可靠是根源:每次跨服务调用都要处理超时/重试/幂等/降级
  • 服务发现 + 配置中心:解决"找谁"和"用什么配置”
  • 数据一致性是最重的税:Saga/最终一致/幂等/对账(下一篇详谈)
  • 可观测性:链路追踪 + 指标 + 日志,否则微服务是黑盒
  • 弹性:超时/重试/熔断/限流/降级/舱壁,防止雪崩
  • 运维:K8s + CI/CD + 网关 + 版本兼容
  • 决策:只有当解耦收益 > 这份税单,才值得拆

下一篇,把最重的一笔税——分布式数据一致性——彻底讲透。