一、全书概览
Sam Newman 的《Building Microservices》是微服务领域绕不开的经典。这本书不是那种读完让你"醍醐灌顶"的灵丹妙药——它更像一本务实的工程手册,把 Netflix、Amazon、Spotify 等公司在微服务实践中踩过的坑、总结出的经验,系统性地整理成了可操作的建议。
全书围绕一个核心问题展开:怎么把一个大泥球(Big Ball of Mud)拆成独立部署、独立演进的微服务,同时不被分布式系统的复杂性搞死?
第一版出版于 2015 年,赶上微服务概念爆发的风口。第二版(2021)做了大量更新,加入了服务网格(Service Mesh)、无服务器(Serverless)、事件驱动架构等新内容。但核心思想没变:微服务不是银弹,它是一种权衡。 如果你把这本书当"微服务圣经"来膜拜,那你大概率会把项目搞砸;如果你把它当作"避坑指南"来参考,它会帮你省下大量试错成本。
全书大约 600 页(第二版),分为五个部分:从单体到微服务的演进、边界划定、集成与通信、数据管理、运维与治理。这个结构本身就反映了 Newman 的工程思维:先想清楚"为什么拆"和"拆什么",再考虑"怎么通信"和"怎么管数据",最后才是"怎么运维"。
个人评价: 这本书最大的优点是诚实。Newman 从不掩饰微服务的代价——运维复杂度指数级上升、调试困难、分布式事务头疼。他反复强调:如果你的团队规模和业务复杂度还没到那个程度,别急着上微服务。这个态度在当年"万物皆可微服务"的狂热氛围里,算是难得的清醒。
二、逐章要点
第1章:微服务概述
Newman 开篇就泼了盆冷水:微服务不是新概念,SOA(面向服务架构)的核心思想早就有了,微服务只是 SOA 的一种特定实现方式。区别在于:微服务更强调独立部署、去中心化治理、小团队全权负责。
💡 核心观点: "如果你无法为你的服务找到一个合理的理由让它独立存在,那它大概不应该成为一个独立的服务。"
| 对比维度 | 单体架构 | 微服务架构 | |---------|---------|-----------| | 部署方式 | 整体部署,牵一发动全身 | 独立部署,互不影响 | | 技术栈 | 统一技术栈 | 每个服务可以自由选择 | | 团队结构 | 大团队集中管理 | 小团队自治(2-pizza team) | | 扩展性 | 整体扩展 | 按需对单个服务扩展 | | 运维复杂度 | 低 | 高(需要服务发现、监控、链路追踪) | | 故障隔离 | 一个模块崩了全崩 | 故障限定在单个服务内 |
关键概念: 限界上下文(Bounded Context)来自领域驱动设计(DDD),是划定服务边界的理论基础。Newman 强调,服务边界应该跟着业务能力走,而不是按技术层(DAO层、Service层、Controller层)来切。
- [ ] 审视现有系统,列出所有可以独立变化的业务模块
- [ ] 评估团队规模:低于 10 人的团队是否真的需要微服务?
- [ ] 梳理部署痛点:单体架构的部署频率是否已经严重制约了开发效率?
第2章:演进式架构
Newman 提出了一个被很多人忽略的观点:不要一步到位把单体拆成微服务。 正确的做法是渐进式演进——先从单体中抽出一个边界清晰的服务,验证独立部署的流程和基础设施是否就绪,再继续拆下一个。
⚠️ 反模式警告: "绞杀者模式"(Strangler Fig Pattern)是 Newman 推荐的迁移策略:新功能用微服务开发,旧功能逐步被替代,直到单体被完全"绞杀"。但很多人错误地把"绞杀者模式"理解为"并行运行新旧两套系统"——这不是绞杀者,这是灾难。
这章最有价值的部分是关于"如何选择第一个拆出去的服务"的建议:
- [ ] 选择变更频率最高的模块(高频变更意味着独立部署收益最大)
- [ ] 选择边界最清晰的模块(减少拆分过程中的依赖纠缠)
- [ ] 先搭好基础设施:CI/CD 流水线、服务注册发现、日志聚合、监控告警
- [ ] 制定回滚策略:拆出去的服务出了问题,能不能快速切回单体?
第3章:服务边界与建模
这章是全书理论密度最高的部分,直接搬了 DDD(领域驱动设计)的大量概念。Newman 的立场很明确:服务边界应该由业务领域决定,而不是技术架构决定。
一个常见的错误是按"数据表"来切服务——每个表一个服务。这会导致服务之间出现大量的事务性依赖,最后变成分布式大泥球。
| 建模方法 | 优点 | 缺点 | 适用场景 | |---------|------|------|---------| | 按业务能力划分 | 服务边界稳定,对齐业务 | 需要深厚的领域知识 | 业务领域成熟的系统 | | 按子域划分 | 符合 DDD 思想 | 学习曲线陡 | 复杂业务系统 | | 按数据流划分 | 技术上直观 | 容易产生细碎服务 | 数据处理管道 | | 按技术功能划分 | 实现简单 | 违反业务内聚 | 不推荐 |
💡 "如果你发现两个服务之间需要频繁同步数据,那说明你的边界划错了。"
Newman 的实操建议:
- 先画出系统的核心业务流程
- 识别出可以独立变化的部分
- 用"信息隐藏"原则来验证边界——每个服务应该对外暴露尽可能少的内部细节
- 不要追求"一步到位"的完美边界,边界是可以调整的
- [ ] 画出当前系统的核心业务流程图
- [ ] 识别出每个流程中"变化频率最高"和"最稳定"的部分
- [ ] 用 API 契约(Contract)来定义服务间的交互,而不是共享数据库
第4章:集成与通信
这章讨论微服务之间怎么"说话"。Newman 把集成方式分成了两大阵营:同步(请求-响应) 和 异步(事件驱动)。
⚠️ "同步调用是分布式系统最大的敌人之一。一个服务变慢,通过调用链传导,可能导致整个系统雪崩。"
Newman 对 REST、gRPC、消息队列的选择建议:
| 通信方式 | 适用场景 | 延迟 | 复杂度 | 容错性 | |---------|---------|------|--------|--------| | REST/HTTP | 对外 API、简单 CRUD | 中 | 低 | 中 | | gRPC | 内部高频调用、需要强类型 | 低 | 中 | 中 | | 消息队列 | 异步处理、解耦、削峰填谷 | 高 | 高 | 高 | | 事件流(Kafka) | 事件溯源、审计日志、CQRS | 中 | 很高 | 很高 |
核心建议:
-
对外暴露 REST API,内部用 gRPC 或消息队列
-
避免服务之间的链式同步调用(A 调 B 调 C 调 D……),超过 3 层就该考虑异步
-
用断路器(Circuit Breaker)保护同步调用,避免级联故障
-
版本化你的 API,破坏性变更必须有新版本
-
[ ] 梳理当前服务间的调用关系图,标注哪些是同步、哪些是异步
-
[ ] 对超过 3 层的同步调用链,评估是否可以改为异步事件驱动
-
[ ] 为所有对外 API 引入版本控制机制
第5章:数据去中心化
这章是很多团队的噩梦。Newman 直说:每个服务应该拥有自己的数据库,服务之间不允许直接访问彼此的数据库。 这条规则违反了很多人的直觉——"我直接查你的表不就行了,为什么要通过 API?"
问题在于,直接访问别人的数据库等于在两个服务之间建立了紧耦合:表结构一变,两个服务都得改。
💡 "共享数据库是分布式系统中的'友敌'——它看起来让你省了事,实际上在暗中破坏你的服务独立性。"
Newman 讨论了几个解决数据一致性的方案:
-
** Saga 模式**:把一个分布式事务拆成一系列本地事务,每个本地事务有对应的补偿操作
-
事件溯源(Event Sourcing):不存储当前状态,存储所有状态变更事件,通过回放事件得到当前状态
-
CQRS(命令查询职责分离):写操作和读操作用不同的模型和数据存储
-
[ ] 检查当前是否有服务直接访问其他服务的数据库——这是必须修复的
-
[ ] 对需要跨服务一致性的场景,评估 Saga 模式的可行性
-
[ ] 考虑引入变更数据捕获(CDC,如 Debezium)来实现数据同步
第6章:测试
微服务测试是个分层工程。Newman 提出了测试金字塔的微服务版本:
/ E2E 测试 \ ← 少量,验证核心业务流程
/ 契约测试 \ ← 中量,验证服务间接口兼容性
/ 集成测试 \ ← 适量,验证服务与外部依赖的交互
/ 组件测试 \ ← 较多,验证单个服务的完整行为
/ 单元测试 \ ← 大量,验证代码逻辑
⚠️ "如果你在微服务中大量依赖端到端测试,你的测试会变得又慢又脆弱,最后没人愿意跑。"
Newman 的关键建议:
-
单元测试 + 组件测试应该占测试的 70% 以上
-
契约测试(Consumer-Driven Contract)是微服务的杀手锏——消费者定义它需要什么,提供者验证它能提供什么
-
用服务虚拟化(Service Virtualization)来模拟外部依赖,避免测试环境的搭建地狱
-
在 CI 流水线中加入消费者契约测试,确保部署不会破坏其他服务
-
[ ] 为每个服务的对外 API 建立契约测试
-
[ ] 搭建服务虚拟化环境,减少对集成环境的依赖
-
[ ] 设定测试覆盖率目标:单元测试 > 80%,组件测试覆盖所有 API 端点
第7章:监控与可观测性
微服务出了问题,你怎么知道是哪个服务挂了?Newman 把可观测性分成三大支柱:
| 支柱 | 工具示例 | 回答的问题 | |------|---------|-----------| | 日志(Logging) | ELK Stack、Fluentd | 发生了什么? | | 指标(Metrics) | Prometheus + Grafana | 系统状态如何? | | 链路追踪(Tracing) | Jaeger、Zipkin | 请求经过了哪些服务?花了多长时间? |
💡 "没有监控的微服务就像没有仪表盘的汽车——你知道它在跑,但你不知道它什么时候会抛锚。"
Newman 强调的几个实操要点:
-
日志必须带 Correlation ID——一个请求跨多个服务时,通过 Correlation ID 把所有日志串起来
-
指标要区分 RED(Rate、Errors、Duration)和 USE(Utilization、Saturation、Errors)——前者面向请求,后者面向资源
-
告警要基于 SLI/SLO,不要拍脑袋设阈值
-
健康检查接口(/health) 是基本要求,但要区分 liveness(活着吗)和 readiness(能接流量吗)
-
[ ] 确保每个服务的日志都包含 trace_id、span_id、correlation_id
-
[ ] 为核心服务定义 SLO(如 99.9% 的请求在 200ms 内完成)
-
[ ] 搭建集中式监控仪表盘,能一眼看到所有服务的健康状态
第8章:部署与运维
最后一章回到最现实的问题:微服务多了,怎么部署和管理?
Newman 的回答是:基础设施即代码(IaC)+ CI/CD 流水线 + 容器化。
⚠️ "如果你还在手动部署微服务,那不是微服务的问题,是流程的问题。手动部署 10 个服务已经够痛苦了,当你有 100 个服务的时候,你会想要自杀。"
这章在第二版中加入了大量关于 Kubernetes、服务网格(Istio、Linkerd)的内容。Newman 的态度比较克制——他不认为每个团队都需要 K8s,小团队用简单的容器编排可能更合适。
核心建议:
-
零停机部署(Blue-Green Deployment 或 Canary Release)是标配
-
配置外部化——不要把配置写死在代码或镜像里
-
用不可变基础设施(Immutable Infrastructure)——每次部署是新镜像,而不是在旧服务器上改配置
-
自动化回滚——部署后监控指标,异常自动回滚到上一版本
-
[ ] 搭建自动化 CI/CD 流水线,实现代码提交到部署的全自动化
-
[ ] 实现金丝雀发布:先灰度 5% 流量,观察指标正常后再全量
-
[ ] 建立部署回滚的标准操作流程(SOP)
三、关键概念速查
1. 限界上下文(Bounded Context)
DDD 中的核心概念。每个限界上下文内部有一套统一的领域模型和语言。微服务的边界应该和限界上下文对齐——一个限界上下文对应一个或多个微服务。跨限界上下文的数据需要通过显式的接口(API 或事件)传递,而不是共享数据库。
典型错误: 把"订单"这个概念在订单服务和库存服务里用不同的字段定义,导致数据不一致。
2. 绞杀者模式(Strangler Fig Pattern)
Martin Fowler 提出的迁移模式。新功能用微服务开发,旧功能留在单体里。通过 API 网关把新旧功能统一对外暴露。随着旧功能逐步被替换,单体最终被完全"绞杀"。名字来源于一种热带植物——它慢慢缠绕宿主树,最终完全覆盖宿主。
关键前提: 你需要一个前置的 API 网关来路由请求到新旧系统。
3. Saga 模式
分布式事务的替代方案。把一个大的分布式事务拆成多个本地事务,每个本地事务执行后发布一个事件,触发下一个本地事务。如果某一步失败,执行一系列补偿操作来撤销之前的变更。
两种实现方式:
- 编排(Orchestration):一个中心协调器控制整个流程(像交响乐团的指挥)
- 协同(Choreography):每个服务自主响应事件,没有中心控制(像爵士乐即兴演奏)
4. 断路器模式(Circuit Breaker)
Michael Nygard 在《Release It!》中提出的模式。当对某个服务的调用失败率达到阈值时,断路器"打开",后续调用直接返回错误(或降级响应),不再尝试调用。过一段时间后进入"半开"状态,试探性放行少量请求,如果成功则"关闭"断路器。
Netflix 开源了 Hystrix(已停止维护),当前推荐使用 Resilience4j。
5. API 网关(API Gateway)
所有外部请求的统一入口。负责路由、认证、限流、协议转换。Newman 强调 API 网关应该保持轻量——不要把业务逻辑塞进去,否则它会变成新的单体。
常见陷阱: API 网关和 BFF(Backend for Frontend)混为一谈。API 网关面向所有客户端,BFF 面向特定前端(如移动端 BFF、Web 端 BFF),可以包含一些聚合逻辑。
6. 消费者驱动契约(Consumer-Driven Contract)
服务消费者定义它期望从提供者那里得到什么响应格式,提供者运行这些契约测试来确保兼容性。Pact 是最流行的契约测试框架。
解决的问题: 提供者改了 API 接口,但不知道会影响到哪些消费者。契约测试让这种破坏性变更在部署前就被发现。
7. CQRS(命令查询职责分离)
把写操作(Command)和读操作(Query)分开处理。写操作修改状态,读操作查询状态。两者可以用不同的数据模型甚至不同的数据库。在微服务中,CQRS 经常和 Event Sourcing 配合使用。
适用场景: 读多写少、读写模型差异大、需要灵活查询的系统。不适用场景:简单的 CRUD 系统——引入 CQRS 纯属过度设计。
四、核心框架/模型
微服务成熟度模型
Level 0: 单体应用,所有功能在一个进程里
Level 1: 微服务化但共享数据库(最差的微服务实现)
Level 2: 独立数据库,同步通信为主
Level 3: 独立数据库,大量使用异步事件驱动
Level 4: 完整的可观测性、自动化运维、服务网格
Newman 的观点是:大多数团队的目标应该是 Level 2-3。Level 4 需要专门的平台工程团队支撑。
服务拆分决策树
这个模块是否需要独立扩展?
├─ 否 → 保持单体
└─ 是 → 这个模块是否需要独立部署/发布?
├─ 否 → 保持单体,用模块化设计
└─ 是 → 这个模块的边界是否清晰?
├─ 否 → 先重构边界,再拆分
└─ 是 → 基础设施是否就绪?
├─ 否 → 先搭基础设施
└─ 是 → 开始拆分
可观测性三支柱模型
┌─────────────────────────────────────────────┐
│ 可观测性(Observability) │
├──────────┬──────────┬───────────────────────┤
│ 日志 │ 指标 │ 链路追踪 │
│ Logging │ Metrics │ Tracing │
│ │ │ │
│ ELK │ Prometheus│ Jaeger/Zipkin │
│ Fluentd │ Grafana │ OpenTelemetry │
│ │ │ │
│ "发生了 │ "系统状态 │ "请求经过了 │
│ 什么?" │ 如何?" │ 哪些服务?" │
└──────────┴──────────┴───────────────────────┘
数据一致性方案选型
| 方案 | 一致性 | 复杂度 | 性能 | 适用场景 | |------|--------|--------|------|---------| | 分布式事务(2PC) | 强一致 | 高 | 低 | 金融交易(越来越少用) | | Saga | 最终一致 | 中 | 高 | 订单处理、库存管理 | | 事件溯源 + CQRS | 最终一致 | 很高 | 中 | 审计要求高的系统 | | 共享数据库(不推荐) | 强一致 | 低 | 中 | 快速原型、过渡方案 |
五、金句摘录
- "微服务不是银弹。它是一种权衡——你用运维复杂度的增加,换取了开发部署的灵活性。如果这个权衡对你的团队和业务不划算,就不要用。"
- "如果你无法用一句话描述一个服务的职责,那它大概率做了太多事情。"
- "最好的架构决策是那些让你在未来可以轻松更改的决策,而不是那些试图一次性解决所有问题的决策。"
- "共享数据库就像是微服务世界里的特洛伊木马——它看起来解决了数据访问的问题,实际上在暗中破坏你所有的服务独立性。"
- "不要为了微服务而微服务。如果你不确定是否需要微服务,那答案大概率是'不需要'。"
- "在任何分布式系统中,网络都是不可靠的。你的代码需要优雅地处理网络分区、超时、重试和部分失败。这不是'额外'的工作,这是'基本'的工作。"
- "API 的版本管理不是可选的——它是必须的。破坏性变更会发生在你身上,而你要么提前规划好,要么在凌晨三点被叫起来救火。"
六、行动清单
🟢 每天
- [ ] 检查核心服务的健康指标(错误率、响应延迟、吞吐量)
- [ ] 关注服务间调用的错误日志,特别是超时和断路器触发事件
- [ ] 确保所有新提交的代码都有对应的单元测试
- [ ] 检查部署流水线是否正常运行
🟡 每周
- [ ] 审查服务间依赖关系图,识别新增的耦合点
- [ ] 回顾本周的线上故障,更新故障复盘文档
- [ ] 检查是否有服务直接访问其他服务的数据库(代码审查重点)
- [ ] 评估各服务的 SLO 达标情况,对未达标的服务制定改进计划
- [ ] 审视是否有新的"共享库"在被多个服务引用——这可能是隐性耦合的信号
🔴 每月
- [ ] 进行一次服务边界的审视——有没有哪个服务变得太大或太小?
- [ ] 更新 API 契约测试,确保消费者和提供者的契约仍然匹配
- [ ] 审查基础设施成本——微服务数量增加带来的资源开销是否在预算内
- [ ] 组织一次"破坏性演练"(Chaos Engineering)——随机关闭一个服务,看系统是否正常降级
- [ ] 评估新技术/工具是否值得引入(新的服务网格方案、可观测性工具等)
七、一句话总结
微服务架构的核心不是技术选型,而是找到正确的服务边界和搭建匹配的工程基础设施——前者决定了你能拆多细,后者决定了你拆了之后能不能活得下去。
八、读者热议
1. "微服务到底适合什么规模的团队?"
这是社区讨论最多的话题之一。Newman 在书中的建议是:微服务的收益和团队规模正相关。一个 3-5 人的团队搞微服务,运维成本会吃掉大部分开发时间。一些资深架构师更激进地认为:50 人以下的团队不应该碰微服务。但也有反例——一些小团队通过使用 Serverless 平台(如 AWS Lambda)把运维负担外包出去,成功在 10 人规模运行了微服务架构。结论是:技术决策要看具体约束条件,不存在放之四海而准的答案。
2. "DDD 太学术了,实践中怎么落地?"
很多读者抱怨 Newman 在第3章大量引用 DDD 概念(聚合根、领域事件、限界上下文),但缺乏具体的实操步骤。社区的一个共识是:不需要完整实施 DDD,只需借用"限界上下文"和"领域事件"这两个概念就够用了。具体做法是:和业务方坐下来,画出核心业务流程,识别出每个步骤中"谁负责什么",自然就能划分出服务边界。过度追求 DDD 的理论完备性,反而会让简单问题复杂化。
3. "Kubernetes 是不是微服务的标配?"
第二版出版后,不少读者讨论 Newman 对 K8s 的"克制"态度。Newman 明确表示 K8s 不是必选项——如果你的服务数量在 20 个以内,Docker Compose + 简单的 CI/CD 可能就够了。一些从 K8s "退回"简单方案的开发者分享了他们的故事:K8s 的学习曲线和运维成本远超预期,最终花了 6 个月搭建 K8s 集群,却只跑了 5 个服务。但也有大规模用户(如 GitLab)证明 K8s 在数百个服务的场景下是不可替代的。关键是:工具匹配问题规模,别用牛刀杀鸡。
笔记生成:2026-04-28 by 喵喵 🐈
相关笔记
同作者仅有此篇 同主题:
七、社区评价
微信读书评分:7.25 分(730 人评) | 总计 5 条热门评论
1. 匿名(👍 0 赞同 💬 0 评论)
2. 匿名(👍 0 赞同 💬 0 评论)
3. 匿名(👍 0 赞同 💬 0 评论)
4. 匿名(👍 0 赞同 💬 0 评论)
5. 匿名(👍 0 赞同 💬 0 评论)
八、争议与批评
请结合豆瓣差评和低分评论,补充本书的主要争议点和批评声音 提示:可搜索
豆瓣 "微服务设计" 差评 批评获取素材