· 王思腾 · 系统架构 · 9 分钟阅读

微服务架构设计:从单体拆分到服务治理

微服务不是银弹,拆得过细反而带来分布式复杂度。本文梳理微服务的边界划分(DDD)、服务间通信、API 网关、服务发现与配置中心,以及熔断限流、可观测性、分布式事务等治理难题,讨论什么时候该拆、什么时候不该拆。

微服务不是银弹,拆得过细反而带来分布式复杂度。本文梳理微服务的边界划分(DDD)、服务间通信、API 网关、服务发现与配置中心,以及熔断限流、可观测性、分布式事务等治理难题,讨论什么时候该拆、什么时候不该拆。

单体应用和微服务的争论从未停止。微服务的吸引力很明显——独立部署、技术栈自由、按服务扩容、团队自治;但它也把进程内调用变成了网络调用,引入了一整套分布式系统的复杂度。微服务的目标不是“拆”,而是让系统在规模增长时依然可开发、可部署、可维护。

一、什么时候该拆,什么时候不该拆

不要为了微服务而微服务。早期团队、业务未定型时,单体(modular monolith)往往是更好的选择:调试简单、事务好做、部署省事。

微服务真正发挥价值的信号:

  • 系统大到单个团队无法掌控,代码互相冲突、发布互相阻塞;
  • 不同模块的资源需求差异巨大(如搜索要大内存、订单要高 IO);
  • 需要独立扩缩容、独立发布节奏;
  • 多团队并行,需要清晰的边界和自治。

经验法则:先把单体写好、模块边界划清,等规模和组织真的需要时再拆。

二、如何划分服务边界

拆分的核心难题是“怎么切”。切错了,服务间频繁耦合调用,比单体还糟。主流指导思想是 领域驱动设计(DDD):

  • 按限界上下文(Bounded Context)划分,每个服务对应一个业务领域(订单、库存、支付、用户);
  • 服务应高内聚、低耦合:一个业务变更尽量只落在一个服务内;
  • 数据归属明确:每个服务拥有自己的数据,不直接读写别人的库,跨服务通过接口或事件交互。

反模式:按技术层切(一个“用户 CRUD 服务”)、或把一个本来内聚的流程硬拆成一堆细粒度服务(纳米服务)。服务不是越小越好,边界正确比数量重要。

三、整体架构与基础设施

一套典型微服务架构包含这些组件:

flowchart TB
    Client["客户端 App / Web"] --> GW["API 网关<br/>鉴权 · 路由 · 限流 · 灰度 · 聚合"]
    GW --> Svc
    subgraph Svc["业务服务"]
        S1["订单"] --- S2["库存"] --- S3["支付"] --- S4["用户"] --- S5["商品"]
    end
    subgraph Gov["服务治理"]
        G1["服务注册发现"] --- G2["配置中心"] --- G3["服务间通信<br/>HTTP / gRPC / MQ"]
    end
    subgraph Infra["基础设施"]
        D1[("MySQL 分库")] --- D2[("Redis")] --- D3["MQ"] --- D4[("ES")] --- D5["链路追踪"]
    end
    Svc -.依赖.-> Gov
    Svc --> Infra
  • API 网关:统一入口,负责鉴权、路由、限流、协议转换、灰度发布;
  • 服务注册与发现:服务实例动态上下线,调用方通过注册中心(Nacos、Consul、Eureka、K8s Service)找到对方;
  • 配置中心:集中管理配置,支持动态刷新;
  • 容器与编排:Kubernetes 已成为微服务部署调度的事实标准,提供弹性伸缩、自愈、服务发现。

四、服务间通信

两种基本风格:

  • 同步调用:HTTP/REST 或 gRPC。gRPC 基于 HTTP/2 + Protobuf,性能高、契约明确,适合内部高频调用;REST 简单通用,适合对外。
  • 异步消息:通过消息队列(Kafka/RocketMQ)发布事件,服务间解耦、削峰。如“订单已支付”事件由支付服务发出,库存、积分、通知各自订阅。

设计原则:

  • 优先用异步事件解耦,减少同步调用链长度(避免 A 调 B、B 调 C、C 调 D 的长链路,一处抖动全链雪崩);
  • 调用要有超时、重试、熔断;
  • 接口要版本化,向后兼容。

五、服务治理:稳定性三板斧

分布式环境下网络不可靠、服务会变慢或宕机,必须有自我保护机制:

  • 超时(Timeout):所有远程调用设超时,避免请求无限堆积拖垮线程池;
  • 重试(Retry):对幂等操作做有限重试(配合退避),非幂等操作慎重试;
  • 熔断(Circuit Breaker):下游持续失败时快速失败、不再压垮对方,半开探测恢复;
  • 限流(Rate Limiting):保护自己不被打满(令牌桶/漏桶);
  • 降级(Fallback):非核心功能失败时返回兜底结果(如推荐挂了返回缓存);
  • 舱壁隔离(Bulkhead):线程池/资源按依赖隔离,避免一个慢依赖耗尽所有资源。

六、分布式事务

单体内一个本地事务就能保证一致性,微服务下一个业务流程跨多个服务、多个库,需要用最终一致性方案(详见电商架构篇):

  • Saga:把长事务拆成一系列本地事务,每步配补偿动作,失败时按序回滚;
  • 本地消息表 / 事务消息:保证“业务写库”和“发消息”原子;
  • TCC:Try-Confirm-Cancel 两阶段,适合强一致要求的资金场景,但侵入性大。

原则:能接受最终一致就别强求强一致,用对账兜底。

七、可观测性

服务一多,“出了问题是哪一跳的锅”会变得极难定位,三大支柱必不可少:

  • 日志(Logging):结构化日志,带统一的 traceId 贯穿一次请求;
  • 指标(Metrics):QPS、延迟 P99、错误率、资源使用率,Prometheus + Grafana;
  • 链路追踪(Tracing):OpenTelemetry / Jaeger / SkyWalking,还原跨服务调用链。

没有可观测性的微服务等于在黑夜里裸奔。

八、常见陷阱

  • 过度拆分:服务数量爆炸,运维和联调成本远超收益;
  • 分布式单体:服务拆了但耦合依旧,改一个功能要动好几个服务、一起发布;
  • 共享数据库:多个服务直连同一个库,边界名存实亡;
  • 忽视数据一致性:用同步调用硬凑分布式事务,又不做补偿和对账;
  • 链路过长:一个请求串行调十几个服务,延迟和故障面成倍放大。

九、小结

  1. 微服务是组织和规模问题的答案,不是技术时髦——小系统用单体,边界清晰的模块化单体甚至能撑很久;
  2. 拆分靠 DDD 限界上下文,追求高内聚低耦合、数据归属清晰;
  3. 基础设施(网关、注册发现、配置中心、K8s)和治理(超时/重试/熔断/限流/降级)缺一不可;
  4. 跨服务一致性用事件驱动 + 最终一致 + 对账,别迷信强一致;
  5. 先把可观测性建起来,否则微服务的复杂度会反噬团队。

拆微服务是一笔用“运维与分布式复杂度”换“团队自治与独立伸缩”的交易——想清楚收益是否覆盖成本,再动手。

本文由 AI 辅助创作,所有内容仅供交流与参考。
分享:
返回博客
电商系统架构设计:从下单到履约的全链路

电商系统架构设计:从下单到履约的全链路

电商系统的复杂性藏在库存、订单、支付与履约的每一次协同里。本文从业务域划分出发,带你走一遍下单主链路,并重点讨论超卖、幂等、分布式事务与大促高并发的应对方案。

分布式锁原理与实践:从 Redis 锁到 Redlock

分布式锁原理与实践:从 Redis 锁到 Redlock

单机锁管不住跨进程、跨节点的并发。分布式锁用于在多实例间互斥访问共享资源(防超卖、防重复任务、幂等)。本文先讲清分布式锁的四大要求(互斥、防死锁、可重入、解铃还须系铃人),再逐个聊 SETNX、Lua 原子性、看门狗续期、Redlock 争议,以及基于数据库/ZooKeeper 的方案与选型。

个人与小团队的全栈技术栈:前端、后端到持续部署,怎么做到低成本、快交付

个人与小团队的全栈技术栈:前端、后端到持续部署,怎么做到低成本、快交付

一个人或两三个人做产品,最大的约束不是技术,是时间和钱。这套栈的目标很明确:不养服务器、不写运维、Git push 就上线、流量小的时候几乎零成本。本文从前端静态优先、后端 Serverless、托管数据库,到 CI/CD 自动部署,给出一套能今天动手、明天上线、跑起来月账单趋近于零的务实组合,顺便拿这个网站本身当例子。