关于 microservices
面向设计或演进微服务系统的团队提供参考,涵盖服务边界、通信与数据模式及弹性设计,也说明何时更适合采用单体架构。
主要功能
- 01微服务与单体架构决策指南
- 02服务拆分策略
- 03同步与异步通信
- 04分布式数据模式
- 05弹性模式参考
适用场景
- 01评估是否拆分单体系统
- 02按业务领域划分服务边界
- 03选择消息传递与一致性模式
- 04规划服务故障处理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ krzysztofsurdy/ code-virtuoso --skill microservices安装后在 Claude Code 中输入/microservices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/communication-patterns.mddata-patterns.mdresilience-patterns.md详细介绍
微服务与分布式系统
微服务架构将系统拆分为可独立部署的服务,每个服务负责一项业务能力。它以牺牲单体架构的简单性为代价,换取扩展、部署和技术选型方面的灵活性。只有在组织和技术复杂度足以证明这种取舍合理时,微服务才能带来收益。
何时使用微服务,何时使用单体架构
这一决策取决于团队规模、领域复杂度和运维成熟度。
| 因素 | 倾向于单体架构 | 倾向于微服务 |
|---|---|---|
| 团队规模 | 小型团队(开发人员少于 10 人) | 需要独立发布周期的多个自治团队 |
| 领域复杂度 | 简单或尚未充分理解的领域 | 已充分理解且限界上下文清晰的领域 |
| 部署频率 | 可以接受不频繁发布 | 系统不同部分需要以不同速度交付 |
| 扩展需求 | 应用各部分的负载较为均匀 | 特定组件需要独立扩展 |
| 运维成熟度 | 基础设施自动化能力有限 | CI/CD、监控和容器编排成熟 |
| 数据隔离 | 共享数据库易于管理 | 服务需要独立的数据存储和架构 |
除非有明确理由,否则从单体架构开始。 结构良好的模块化单体日后可以拆分。过早采用微服务架构会带来分布式系统的复杂性,却没有相应的收益。
服务拆分策略
划定服务边界是最困难的部分。如果划分不当,就会得到一个分布式单体:承担了分布式架构的所有成本,却没有获得任何好处。
按业务能力拆分
服务应与组织的业务相对应,而不是与软件的结构相对应。每个服务映射到一项业务职能:订单管理、库存、计费、通知。服务会随其代表的业务能力变化而变化。
按子域拆分(领域驱动设计)
使用领域驱动设计中的限界上下文来识别自然边界。每个限界上下文都有自己的通用语言和内部模型。计费上下文中的“客户”可能与配送上下文中的“客户”具有不同属性。这没有问题。
绞杀者无花果迁移
从单体架构迁移时,应逐个提取服务,而不是一次性重写。通过门面转发流量:默认委托给单体架构,但随着新服务逐步构建,将特定业务能力的流量重定向到新服务。随着时间推移,单体架构会逐渐缩小,直到可以退役。迁移期间,反腐层负责在新旧模型之间进行转换。
拆分经验法则
- 候选项之间耦合度高:将它们放在一起,它们很可能属于同一个服务
- 变化频率不同:将它们拆分,以便独立部署
- 扩展特征不同:将它们拆分,因为它们需要不同的资源分配
- 共享数据:如果两个候选项总是读写相同的表,拆分它们只会增加网络通信,不会带来收益
通信模式
服务必须相互通信,而选择同步还是异步交互,会影响整个系统的行为。
| 风格 | 机制 | 优势 | 劣势 |
|---|---|---|---|
| 同步请求-响应 | REST、gRPC、GraphQL | 心智模型简单,可立即获得响应 | 时间耦合、故障级联 |
| 异步消息传递 | 消息队列(点对点) | 解耦发送方与接收方,可在负载过高时缓冲 | 需要额外基础设施、最终一致性 |
| 事件驱动 | 事件总线、发布/订阅 | 松耦合,可支持多个使用者 | 更难调试、事件顺序方面的挑战 |
经验法则: 对于需要立即获得答案的查询,使用同步调用。对于发送方无需等待结果的命令和事件,使用异步消息传递。
参见通信模式参考,了解 API 网关、服务发现、gRPC、服务网格和边车模式。
分布式系统中的数据管理
每个服务都应拥有自己的数据。共享数据库会造成隐性耦合,破坏服务独立性。数据所有权也会带来一致性和跨服务事务方面的新问题。
核心原则
- 每个服务使用独立数据库:每个服务都有自己的数据存储,只能通过其 API 访问
- 不直接共享数据库:如果其他服务需要数据,应通过拥有该数据的服务接口请求
- 最终一致性是常态:跨服务实现强一致性需要分布式事务,而分布式事务既脆弱又缓慢
- 根据服务选择数据存储:不同服务可根据其访问模式使用不同的数据库技术
核心数据模式
| 模式 | 用途 |
|---|---|
| CQRS | 分离读模型和写模型,分别进行优化 |
| 事件溯源 | 将状态存储为不可变事件序列,而非覆盖当前状态 |
| Saga | 通过一系列本地事务和补偿操作协调多服务事务 |
| Outbox | 在同一数据库事务中将事件写入本地表,以确保可靠发布 |
| 最终一致性 | 接受服务间的数据会随时间逐渐收敛,而非立即保持一致 |
参见数据模式参考,了解包含多语言示例的实现细节。
弹性模式
在分布式系统中,故障时有发生。网络分区、依赖项响应缓慢以及服务过载都是常见的运行状况。弹性模式可防止局部故障在系统中级联传播。
模式概要
| 模式 | 用途 |
|---|---|
| 熔断器 | 停止调用故障依赖项;快速失败,并给它恢复时间 |
| 舱壁 | 隔离资源池,避免某个响应缓慢的依赖项耗尽其他依赖项所需的资源 |
| 带退避的重试 | 以逐渐增加的延迟和随机抖动重试瞬时故障 |
| 超时 | 为等待响应的时长设置上限;绝不无限期阻塞 |
| 回退 | 依赖项不可用时,提供功能有所缩减但仍可工作的行为 |
| 健康检查 | 提供存活和就绪端点,让编排器能够路由流量并重启不健康的实例 |
参见弹性模式参考,了解包含多语言示例的实现细节。
参考文件
| 参考 | 内容 |
|---|---|
| 数据模式 | CQRS、事件溯源、Saga 编排与协同、Outbox 模式、最终一致性,附多种语言示例 |
| 弹性模式 | 熔断器、舱壁、带退避的重试、超时、回退、健康检查,附多种语言示例 |
| 通信模式 | REST、gRPC、GraphQL 联邦、消息队列、API 网关、服务发现、Sidecar 和服务网格,附多种语言示例 |
与其他技能集成
| 情况 | 推荐技能 |
|---|---|
| 领域建模和限界上下文设计 | clean-architecture |
| 微服务测试(契约测试、集成测试) | testing |
| 服务接口的 API 设计 | api-design |
| 单个服务的性能调优 | performance |