mcpField
S
service-decomposition

service-decomposition

github.com/proyecto26开发113361 次安装1 天前更新
代码仓库

关于 service-decomposition

帮助架构师和开发团队决定系统是否应拆分为可独立部署的服务,并选择边界与通信方式。内容涵盖单体、模块化单体和微服务的权衡,以及拆分后的故障与运维影响。

主要功能

  1. 01评估单体与微服务方案
  2. 02按业务能力划分边界
  3. 03选择同步或异步通信
  4. 04权衡网关、服务发现与网格
  5. 05检查跨服务故障风险

适用场景

  1. 01评估是否应新增可独立部署的服务
  2. 02为不同扩展需求划分服务
  3. 03规划服务间通信与发现机制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/proyecto26/system-design-skills --skill service-decomposition

安装后在 Claude Code 中输入/service-decomposition确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
deep-dive.md
references/providers/
aws.md
azure.md
gcp.md
generic.md

详细介绍

服务拆分

确定如何将系统拆分为可部署的服务——或者是否需要拆分——以及这些服务如何相互发现并调用。这是设计的“应用层”:它位于边缘层(dns/load-balancing/`content-delivery)和数据层之间。服务的粒度把握不当,无论偏向哪一端,都会成为分布式系统中代价最高的错误之一。

两种极端都会带来问题。一个庞大的服务无法让团队或组件独立扩展;一大群微小服务则会让你淹没在网络跳数、局部故障和难以调试的跨服务跟踪中。关键在于为当前规模的这个系统找到恰到好处的平衡点,而不是一味增加服务数量。

适用场景

计划新增第二个服务;团队需要独立部署;某个部分的扩缩容特征与其他部分截然不同;或现有系统“通信过于频繁”/难以更改。此外,当有人默认提议采用“微服务”时,也适用。

不适用场景

新产品/小团队/尚未验证的领域——从单体(或模块化单体)开始,等真正出现明确的边界和理由后再拆分。过早拆分会带来分布式系统的成本(网络故障、最终一致性、运维),却只是为了解决一个尚不存在的问题(YAGNI,GUIDE #7)。在还没有需要它们的服务之前,不要添加网关/网格/服务发现层。

先明确以下事项

  • 团队与部署独立性——不同部分是否必须由不同负责人按不同节奏发布?
  • 扩缩容差异——某个组件是否需要其他组件 100 倍的资源?
  • 耦合度——哪些部分会一起变化(应归在一起),哪些部分会各自演进?
  • 延迟预算——有多少进程内调用会变成网络跳数?
  • 边界两侧的一致性——拆分后,服务之间能否容忍最终一致性?(→ consistency-coordination)

选项

  • 单体——一个可部署单元。适用场景:新项目/小项目、快速迭代、强跨模块事务、单一团队。
  • 模块化单体——一个可部署单元,内部模块边界受到强制约束。适用场景:想要清晰的边界,但暂不承担网络开销——这是“我们以后或许会拆分”的最佳默认选择。
  • 微服务——按业务能力/限界上下文拆分为多个小型可部署单元。适用场景:独立部署/扩缩容/归属管理确实值得承担分布式系统的成本。
  • 通信方式——只需针对每个边界决定采用同步(REST/gRPC,请求/响应,简单但会耦合可用性)还是异步(解耦但最终一致)。本节只决定每个边界采用同步还是异步;不负责异步机制——边界一旦采用异步,就调用 messaging-streaming,以确定交付保证、顺序、背压和 DLQ 语义,确保安全。不要仅凭“无需立即得到答复”这一句规则就选择异步,而不深入了解这些故障模式。大多数系统会混合采用两种方式。
  • 服务层边缘——采用API 网关/BFF(统一入口:身份验证、路由、速率限制、聚合),还是直接暴露服务。
  • 相互发现——采用服务发现(注册表:基于 DNS,或使用 etcd/Consul/ZooKeeper),并可选用服务网格(通过 Sidecar 实现 mTLS、重试、流量整形),还是使用库级客户端。

权衡

选项解决的问题带来的问题何时调整
单体简单;进程内调用;事务和调试容易部署/扩展相互耦合;团队成为瓶颈;故障影响范围大团队/规模的需求出现分化 → 模块化单体 → 拆分一个边界
模块化单体边界清晰、没有网络开销、可选择日后拆分仍然需要统一部署;需要遵守纪律来保持模块边界清晰某个模块需要独立部署/扩展 → 将其提取为服务
微服务每项能力都可独立部署/扩展/归属网络故障、最终一致性、分布式调试、运维协调/延迟成本超过独立性的收益 → 合并
同步通信思维模型简单,能立即得到结果可用性相互耦合(被调用方失败时调用方也失败);延迟累积调用不需要立即返回结果时 → 异步(messaging-streaming)
API 网关 / BFF为认证/路由/速率限制/聚合提供统一入口增加一层 + 潜在的单点故障/瓶颈;可能演变成迷你单体逐渐积累业务逻辑时 → 将逻辑移回服务
服务网格无需更改应用即可统一实现 mTLS/重试/可观测性带来实际的运维和延迟开销(边车)服务只有少数几个时 → 使用库/网关就足够

压力下的表现

  • 服务间调用频繁 / 扇出: 一个用户请求会变成 N 次同步内部调用;尾延迟会累积,单个缓慢依赖也会阻塞整个调用链。 缓解: 使用更粗粒度的边界、批处理、无需立即得到答案时采用异步,并使用熔断器(→ resilience-failure)。
  • 分布式事务问题: 跨服务的写入无法组成一个 ACID 事务。缓解: 使用 saga / outbox,或将数据保留在同一个服务中,让事务保持在本地(→ consistency-coordination)。
  • 网格中的重试风暴: 朴素重试会将过载放大为级联故障。缓解: 退避 + 抖动、重试预算、熔断器(→ resilience-failure)。
  • 可调试性崩溃: 没有关联 ID / 跟踪时,跨越 6 个服务的故障会无从察觉。缓解: 从第一天起就使用分布式跟踪 + 关联 ID(→ observability、distributed-logging)。
  • 网关/服务发现成为单点故障: 如果入口或注册表宕机,一切都会停止。缓解: 使用冗余、在客户端缓存服务发现结果、进行健康检查。

如何应用

  1. 明确驱动因素 — 需要独立部署?差异化扩展?团队所有权?如果这些需求都还不是真实存在的,就此打住:选择(模块化)单体更合适。
  2. 默认选择满足需求的最简单方案 — 单体 → 模块化单体 → 仅提取确有理由拆分的边界,而不是“所有东西都做成服务”。
  3. 按业务能力 / 限界上下文划分边界,让数据及其所属逻辑保持在一起(尽量减少跨服务事务)。
  4. 针对每次调用选择通信方式 — 仅当调用方需要立即得到答案时才采用同步;否则采用异步(→ messaging-streaming)。
  5. 仅在确有需要时添加统一入口 + 服务发现 — 使用网关/BFF 处理认证/路由/聚合;当服务数量使静态配置变得繁琐时,再采用服务发现/网格。
  6. 对边界进行压力测试 — 在作出决定前,检查频繁调用、跨服务事务、重试级联和跟踪能力。
  7. 在答案中说明权衡 — 提供一张 Decision | Solves | Worsens | Change it when… 表格,为此处作出的每项选择各列一行(例如选项、其存储、其故障策略);最后一列应为具体触发条件(某个数字或可观察信号)。然后说明最先会出现什么故障。

该做与不该做

该做

  • 从单体/模块化单体开始;只有出现实际需求时才拆分边界。
  • 按业务能力拆分,让服务拥有自己的数据(使事务保持在本地)。
  • 从一开始就为每次跨服务调用添加关联 ID 和追踪。
  • 合理控制规模:少量边界清晰的服务胜过大量细碎、频繁通信的服务。

不该做

  • 不要默认选择微服务,也不要为了简历而选择微服务(GUIDE #7)。
  • 不要创建一个写入操作需要在同一事务中使用其他服务数据的服务。
  • 不要让 API 网关不断累积业务逻辑,变成一个隐藏的单体。
  • 只有少数几个服务时,不要添加服务网格——其开销得不偿失。

重要指标

每次同步调用都会增加一次同数据中心的往返延迟(约 0.5 ms),还要加上被调用方自身的处理时间。10 次串行调用的网络耗时也只有约 5 ms——真正的成本在于叠加的p99/序列化/排队/重试尾延迟:每次调用都会提高遇到慢依赖的概率,因此端到端 p99 的恶化远快于平均值。拆分之前,要评估调用图深度和每次调用的 p99(而不只是网络耗时),并明确设定 p99 预算。→ back-of-the-envelope。

接口草图

服务边界是一份契约:归属数据(每个实体由哪个服务作为事实来源)、服务暴露的 API(→ api-design),以及服务发出的事件(→ messaging-streaming)。在画服务框图之前,先写清楚“用户记录归谁所有、订单归谁所有”——跨越边界共享可变数据是头号拆分异味。

选择提供商

默认采用上面的通用方案。如果用户指定了云平台,请阅读 references/providers/<provider>.md,了解托管网关/服务发现/服务网格的对应方案、限制和权衡。如果该提供商没有对应文件,则采用通用方案。

图示

如需将服务层可视化(网关 → 服务 → 各自的数据,并标出同步与异步连接及信任边界),请使用插件内的 architecture-diagram 技能。

相关构建模块

  • api-design — 与本模块配合:拆分决定边界,api-design 定义每个服务的契约。
  • messaging-streaming — 与本模块配合:用于服务间异步/事件驱动通信(是同步耦合的替代方案)。
  • consistency-coordination — 负责跨服务一致性方案(Saga/2PC)以及服务协调理论,包括服务发现(领导者选举、etcd/Consul/ZooKeeper);请链接到该模块,不要在此重复讲解。
  • resilience-failure — 依赖本模块:断路器、超时和舱壁可防止频繁通信的网格发生级联故障。
  • observability + distributed-logging — 为本模块提供支撑:追踪和关联 ID 能让多服务请求变得可调试。
  • scaling-evolution — 为本模块提供支撑:提取服务是“拆分边界”这一演进阶段上的一种扩展举措。
  • system-design — 编排者。

参考资料

  • references/deep-dive.md — 限界上下文及如何寻找拆分边界、从单体迁移的绞杀者模式、网关与 BFF 和服务网格的比较、同步与异步决策详情、跨服务写入的 Saga/outbox,以及粒度反模式(纳米服务、分布式单体、共享数据库)。
  • references/providers/{generic,aws,azure,gcp}.md — 不同环境下网关/服务发现/服务网格服务的映射、限制和陷阱。

评论

支持 Markdown