微服务:把一个文件拆成一支服务队¶
1. 这一章讲什么¶
微服务不是一个产品而是一种架构风格:把应用拆成一组小而自治、各自管一件明确的事、能独立部署的服务1。这一章的上半部回答「为什么这么拆、怎么拆、拆完得到什么、付出什么」,下半部回答一个拆完才会遇到的问题:服务们隔着网络,怎么互相说话、怎么把话说清楚。
2. 顶层全景¶
一个应用的三种活法(全章主线:SmartBuilding 应用):
① 单文件单体 SmartBuilding.py —— 所有功能挤在一个文件
② 模块化 read.py / preprocess.py / stats.py / publish.py / frontend.py —— 分文件,但仍跑在一个进程里
③ 微服务 ConsumeData / Preprocess / Analytics / Publish / Frontend —— 五个独立部署的服务,走网络通信
下半部的地图:服务间通信三件套(HTTP/REST、gRPC、消息队列)× 两种节奏(同步等响应、异步不等)× 一个总入口(API 网关)× 一份说清 API 的契约(OpenAPI)。
3. 核心原理¶
3.1 从哪来:模块化 → SOA → 微服务¶
1960–70 年代的模块化编程主张把软件分成独立模块,靠封装(藏住内部)和内聚(一个模块只做一类事)协作2。1990 年代到 2000 年代初,SOA(面向服务的架构) 把模块拆到了网络边界上:商品列表、结账、用户认证变成「库存服务」「支付服务」「认证服务」,各自可能跑在不同服务器上3。
但 SOA 有五个病,书里列得清楚4:
- 复杂且重:靠 ESB(企业服务总线)这类重量级中间件管通信,容易成瓶颈;
- 粒度太粗:服务块头太大,不能精准地扩某一个功能;
- 紧耦合:共享库、集中治理让服务互相绑死;
- 部署和扩容笨:小改动要重新部署一大块;扩容只能整包扩;
- 开发慢:标准化、审批式治理拖住迭代。
2011 年「microservices」一词在一个威尼斯工作坊上出现,2012 年 James Lewis 和 Martin Fowler 在巴西研讨,2014 年 Fowler 那篇著名博文把概念推向业界5。此后 Docker、Kubernetes 等工具链把「部署几千个小服务」从不可能变成日常。
3.2 主线例子:SmartBuilding 的三次投胎¶
一个处理楼宇 IoT 数据的应用,书里用它的三次重构讲透了架构演化的逻辑。
第一世:单文件。SmartBuilding.py 一个文件装下所有功能函数:read() 读 CSV 数据、outlier() 和 missing() 清洗、mean()/min()/max() 算统计、pushToMongo() 和 pushToS3() 存存储、viz() 画图6。病在哪?书里点了四个:可视化功能流量大、分析功能流量小,但扩容只能整包扩;想从 Python 2.7 升到 3.10 要动全身;文件越加越大难维护;一个函数挂了(比如数据库交互),整个应用全灭——单点故障7。
第二世:模块化。拆成五个文件:read.py(读数据)、preprocess.py(清洗)、stats.py(统计)、publish.py(发布到 MongoDB/S3)、frontend.py(可视化)8。代码清爽了,但病还在:模块间互相依赖改一牵三;集成测试仍然复杂;共享数据模型一处变处处变;最关键的是仍跑在一个运行时里,stats.py 想单独多开一份副本,做不到9。
第三世:微服务。五个模块升级成五个服务:ConsumeData、Preprocess、Analytics、Publish、Frontend,各自独立部署、各自扩缩10。此时通信方式从「函数直接调用」变成「网络调用」——这就是后半章的全部主题。
瑞士军刀类比(书里原话):单体像瑞士军刀,一个紧凑单元集齐刀/螺丝刀/剪刀;方便,但单个工具不如专做的顺手,一个工具坏了要修整把刀,想只放大其中一个工具则必然整把变大11。好处也公允:单一代码库上手快、部署一个包就行、本地一台机器就能跑起来调试、事务完整性天然成立、初创成本低12。
3.3 怎么拆:四条判据¶
拆错了比不拆更糟。书里给四条13:
- DDD(领域驱动设计):找业务上的天然边界,每个服务包住一个「限界上下文」。在线书店的例子:书目管理、订单管理、支付处理、物流配送各自成服务14。
- 业务能力:围绕「用户管理」「订单管理」这类稳定的价值单元切。
- 扩容需求:负载波动大、增长快的组件,独立成服务才能单独扩。
- 性能与韧性:关键组件隔离出来,防止故障级联成单点故障。
切多细也有代价(fine-grained 的四个坑):重复造轮子(三个金融服务各自写一套身份校验)、重复基建、每次网络调用都有延迟,链一长延迟叠起来、以及管理成本15。书里一句话收束:不是拆了就变好,「切之前需要仔细的策略」15。
3.4 服务之间怎么说话¶
HTTP:请求-响应模型,建立在 TCP(传输控制协议)之上(三次握手:双方互发三个确认包来建立连接)。一个请求 = 方法(GET/POST/PUT/DELETE)+ 资源路径 + 版本 + 头部(header,附加说明信息);响应 = 状态行(如 HTTP/1.1 200 OK)+ 头部 + 正文16。这四个方法正好对应 CRUD(增删改查)17。HTTP 的无状态特性恰好对上微服务:每次请求自带全部上下文,服务想扩几份扩几份18。
gRPC:Google 的高性能 RPC 框架。默认用 Protocol Buffers(.proto 文件定义接口,自动生成各语言代码,比 JSON/XML 更小更快)走 HTTP/2(头部压缩、单连接多路复用),原生支持四种流:一问一答、服务器推流、客户端推流、双向流19。书里的一句话定位:gRPC 用于服务内部通信、要低延迟的场景;HTTP/REST 胜在简单通用20。
消息队列:生产者和消费者互不认识,中间隔着队列(broker),消息存着等消费者有空来取——RabbitMQ、Kafka、AWS SQS、Azure Service Bus 都是实现;broker 之间多用 AMQP 等二进制协议而非 HTTP21。
同步 vs 异步,用同一个书店结账流程对照(这是全章第二条主线例子,务必记住):
- 同步版:购物车 → 查库存 → 算价 → 支付 → 确认订单,五步串成一条链,每步都等上一步的响应,客户从头等到尾;任何一个环节慢,整条链卡死22。
- 异步版:订单服务收下订单立刻回客户「已收到」;然后库存扣减、支付处理、发货准备、邮件通知全部丢进队列各干各的;通知服务订了「支付成功」事件,触发确认邮件。客户不等;某个环节挂了,其他环节照跑23。
判据一句话:这条消息的发送方需不需要立刻知道结果? 需要(如支付授权)= 同步;不需要(如发通知、建索引)= 异步24。另有一对维度:一对一(查库存)与一对多(「新书上架」事件广播给推荐、营销、前台三个订户)25。
3.5 REST 与 API 网关:把话说清楚、把门看好¶
光有 HTTP 不够:/getDetails?id=123 这种端点不可读、各家命名五花八门(/fetchUser vs /getUserInfo)。REST(表述性状态转移) 是套架构原则:把 URL 当资源名(如 /api/openstacktenant-instances?page=24),用 HTTP 方法表达动作,状态码表达结果26。书里拆了一个真实请求:https://api.etais.ee/api/openstacktenant-instances?page=24 = 协议(https)+ 域名 + 资源路径 + 查询参数(第 24 页)27。
API 网关是所有外部流量的唯一入口,像交警28。没有它,手机 App、智能电视、网页各自直连每个微服务,每个服务都要为每种设备定制响应——乱。网关统一承担六件事:认证(查令牌)、监控(记谁在调)、负载均衡、请求路由(看照片的请求转给照片服务)、组合(把「资料+交易记录+设置」三个服务的调用合成一次响应)、协议转换(老 SOAP 转新 JSON)29。
OpenAPI:描述 REST API 的标准格式,让机器和人不看源码就懂你的 API。它前身是 Tony Tam 2011 年做的 Swagger 规范,2015 年捐给 Linux 基金会下的 OpenAPI Initiative 改名30。一份 OpenAPI 文档五个段:info(标题版本)、servers(地址)、paths(端点和方法,必填)、components(可复用的数据模型)、security(认证方式)31。书里给了 SmartBuilding 的完整样例:一个 POST /Device 端点,加设备的请求体引用 Device schema,错误返回 405,安全要求 write:Devices 权限32。配套三件套:Swagger Editor(左边写 YAML 右边出预览)、Swagger UI(把文档变成可点可试的网页)、Codegen(从文档生成服务端骨架和客户端库)33。
3.6 微服务的病,答案是下一章¶
部署几百上千个服务,每个依赖不同、配置不同、环境难一致、资源互相争抢——这些是微服务自己的病。书里指了明路:容器化。把每个服务和它的全部依赖打进一个可部署的包,环境一致了、隔离有了、扩缩快了——第 6 章的主题34。
4. 作者的判断与证据¶
有出处的:Fowler/Lewis 微服务定义与 2014 年博文5;SOA 的五宗罪有文献引用4;瑞士军刀类比、两披萨团队(团队小到一个披萨能喂饱)是行业通行比喻35。
作者自己的判断:「微服务不是 DevOps 的必要条件,单体也能做 DevOps」(第 1 章同口径)在 4.9 的论证里得到呼应——书里把微服务与 DevOps 的关系说成「互相成就」而非「前提」36。
值得警惕的:参考文献里藏着一篇 Istio 团队「从微服务迁回单体」的经验(IEEE Software 2021,ref [14])——书正文没讲这个案例,但文献表承认了这个反例的存在。我们把它点出来:拆不拆,看团队运维能力,不看潮流。
5. 边界与局限¶
- 分布式数据管理(每个服务一个数据库?跨服务事务怎么办?)书里只在复习题里出现37,正文没讲——这是微服务落地最硬的问题之一,需另读(如 Saga 模式)。
- service mesh(服务网格)只在复习题点名37。
- gRPC、GraphQL、serverless 都点到为止,明说「请查专门资料」1938。
- 性能对比(微服务 vs 单体的延迟/吞吐实测)未给数据,只有定性讨论。
6. 可带走的¶
- 架构演化是治病链:单文件→模块(治混乱)→微服务(治单点故障和扩容粒度),每步都有新病79。
- 单体不是垃圾:小应用、原型、初创阶段,单体更快更省12。
- 拆服务的四条判据:领域边界、业务能力、扩容需求、故障隔离13。
- 切太细 = 重复造轮子 + 延迟叠加;「怎么拆」比「拆不拆」更决定成败15。
- 通信选型一句话:要即时结果选同步(HTTP/gRPC),不需要等选异步(消息队列);内部高性能选 gRPC,外部通用选 REST1924。
- API 网关是外部流量的唯一入口:认证、路由、组合、限流都在这一层做2829。
- OpenAPI 文档是服务的契约,五段结构(paths 必填);Swagger Editor/UI/Codegen 三件套围绕它转3133。
- 微服务五大运维病(部署复杂、开销、环境不一致、资源争抢、扩缩管理)指向同一个答案:容器——下一章34。
7. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| SOA 的五个问题 | 4 - Microservices | text/09-ch04-4-microservices.txt:61(搜「Complexity and Overhead」) |
| 微服务命名史(2011/2014 Fowler) | 4 - Microservices | text/09-ch04-4-microservices.txt:39(搜「coined by Martin Fowler」) · text/09-ch04-4-microservices.txt:47(搜「detailed blog post in 2014」) |
| SmartBuilding 单文件版 | 4 - Microservices | text/09-ch04-4-microservices.txt:106(搜「read() function to read IoT data」) |
| 单体四病(扩容/升级/复杂/单点) | 4 - Microservices | text/09-ch04-4-microservices.txt:114(搜「high demand for the data visualization」) |
| 模块化八条局限 | 4 - Microservices | text/09-ch04-4-microservices.txt:155(搜「Intermodule Dependencies」) |
| 五个微服务划分 | 4 - Microservices | text/09-ch04-4-microservices.txt:187(搜「ConsumeData Service」) |
| 瑞士军刀类比 | 4 - Microservices | text/09-ch04-4-microservices.txt:200(搜「Swiss Army knife」) |
| 拆分的四条方法论(DDD 等) | 4 - Microservices | text/09-ch04-4-microservices.txt:303(搜「Domain-Driven Design」) |
| 细粒度的四个坑 | 4 - Microservices | text/09-ch04-4-microservices.txt:328(搜「Overhead Redundancy」) |
| HTTP 请求/响应结构 | 4 - Microservices | text/09-ch04-4-microservices.txt:424(搜「HTTP Method」) |
| gRPC 与四种流 | 4 - Microservices | text/09-ch04-4-microservices.txt:494(搜「developed by Google」) · text/09-ch04-4-microservices.txt:503(搜「unary RPC」) |
| 消息队列与 broker | 4 - Microservices | text/09-ch04-4-microservices.txt:525(搜「intermediary layer」) |
| 同步结账十二步 | 4 - Microservices | text/09-ch04-4-microservices.txt:565(搜「Shopping Cart service to retrieve」) |
| 异步订单流程 | 4 - Microservices | text/09-ch04-4-microservices.txt:628(搜「greatly enhance the user experience」) |
| REST 请求拆解(ETAIS 例) | 4 - Microservices | text/09-ch04-4-microservices.txt:731(搜「24th page」) |
| AWS EC2 curl 实例 | 4 - Microservices | text/09-ch04-4-microservices.txt:765(搜「RunInstances」) |
| API 网关六职责 | 4 - Microservices | text/09-ch04-4-microservices.txt:805(搜「traffic cop」) |
| OpenAPI 历史(Swagger→OAI) | 4 - Microservices | text/09-ch04-4-microservices.txt:837(搜「Tony Tam in 2011」) |
| OpenAPI 文档五段 | 4 - Microservices | text/09-ch04-4-microservices.txt:882(搜「paths: As a mandatory part」) |
| 微服务五大病→容器 | 4 - Microservices | text/09-ch04-4-microservices.txt:963(搜「Complexity in Deployment」) |
| Istio 迁回单体(文献反例) | 4 - Microservices | text/09-ch04-4-microservices.txt:1114(搜「monolith strikes back」) |
-
出处:「4 - Microservices」第 5–7 段(
text/09-ch04-4-microservices.txt:6,搜「collection of small, autonomous services」)。 ↩ -
出处:「4 - Microservices」第 19–26 段(
text/09-ch04-4-microservices.txt:23,搜「encapsulation」)。 ↩ -
出处:「4 - Microservices」第 27–38 段(
text/09-ch04-4-microservices.txt:33,搜「across network boundaries」)。 ↩ -
出处:「4 - Microservices」第 60–77 段(
text/09-ch04-4-microservices.txt:61,搜「Complexity and Overhead」)。 ↩↩ -
出处:「4 - Microservices」第 39–47 段(
text/09-ch04-4-microservices.txt:39,搜「coined by Martin Fowler」)。 ↩↩ -
出处:「4 - Microservices」第 105–112 段(
text/09-ch04-4-microservices.txt:106,搜「read() function」)。 ↩ -
出处:「4 - Microservices」第 114–127 段(
text/09-ch04-4-microservices.txt:115,搜「scaling the entire application」;:123搜「single point of failure」)。 ↩↩ -
出处:「4 - Microservices」第 136–151 段(
text/09-ch04-4-microservices.txt:137,搜「Read Module」)。 ↩ -
出处:「4 - Microservices」第 153–181 段(
text/09-ch04-4-microservices.txt:175,搜「limits the ability to scale out」)。 ↩↩ -
出处:「4 - Microservices」第 184–191 段(
text/09-ch04-4-microservices.txt:187,搜「ConsumeData Service」)。 ↩ -
出处:「4 - Microservices」第 200–214 段(
text/09-ch04-4-microservices.txt:200,搜「Swiss Army knife」)。 ↩ -
出处:「4 - Microservices」第 234–253 段(
text/09-ch04-4-microservices.txt:234,搜「easier to develop initially」)。 ↩↩ -
出处:「4 - Microservices」第 297–322 段(
text/09-ch04-4-microservices.txt:303,搜「Domain-Driven Design」)。 ↩↩ -
出处:「4 - Microservices」第 306–311 段(
text/09-ch04-4-microservices.txt:306,搜「online bookstore」)。 ↩ -
出处:「4 - Microservices」第 325–342 段(
text/09-ch04-4-microservices.txt:328,搜「Overhead Redundancy」;:342搜「careful strategy」)。 ↩↩↩ -
出处:「4 - Microservices」第 393–443 段(
text/09-ch04-4-microservices.txt:424,搜「GET, POST, PUT, DELETE」;:433搜「200 OK」)。 ↩ -
出处:「4 - Microservices」第 445–465 段(
text/09-ch04-4-microservices.txt:462,搜「CRUD」)。 ↩ -
出处:「4 - Microservices」第 467–491 段(
text/09-ch04-4-microservices.txt:473,搜「stateless protocol」)。 ↩ -
出处:「4 - Microservices」第 493–506 段(
text/09-ch04-4-microservices.txt:494,搜「developed by Google」)。 ↩↩↩ -
出处:「4 - Microservices」第 508–520 段(
text/09-ch04-4-microservices.txt:519,搜「internal communication」)。 ↩ -
出处:「4 - Microservices」第 522–544 段(
text/09-ch04-4-microservices.txt:532,搜「broker」)。 ↩ -
出处:「4 - Microservices」第 553–600 段(
text/09-ch04-4-microservices.txt:565,搜「routes the initial request to the Shopping Cart」)。 ↩ -
出处:「4 - Microservices」第 603–659 段(
text/09-ch04-4-microservices.txt:632,搜「receives the order details」)。 ↩ -
出处:「4 - Microservices」第 546–551 段(
text/09-ch04-4-microservices.txt:550,搜「synchronous and asynchronous」)。 ↩↩ -
出处:「4 - Microservices」第 661–680 段(
text/09-ch04-4-microservices.txt:664,搜「exactly one service」;:676搜「New Book Added」)。 ↩ -
出处:「4 - Microservices」第 682–729 段(
text/09-ch04-4-microservices.txt:710,搜「Representational State Transfer」)。 ↩ -
出处:「4 - Microservices」第 730–746 段(
text/09-ch04-4-microservices.txt:740,搜「Resource Path」)。 ↩ -
出处:「4 - Microservices」第 780–807 段(
text/09-ch04-4-microservices.txt:805,搜「traffic cop」)。 ↩↩ -
出处:「4 - Microservices」第 808–825 段(
text/09-ch04-4-microservices.txt:811,搜「Authentication」)。 ↩↩ -
出处:「4 - Microservices」第 836–840 段(
text/09-ch04-4-microservices.txt:837,搜「Tony Tam in 2011」)。 ↩ -
出处:「4 - Microservices」第 877–890 段(
text/09-ch04-4-microservices.txt:882,搜「paths: As a mandatory part」)。 ↩↩ -
出处:「4 - Microservices」第 899–953 段(
text/09-ch04-4-microservices.txt:900,搜「/Device」)。 ↩ -
出处:「4 - Microservices」第 841–849 段(
text/09-ch04-4-microservices.txt:846,搜「Swagger UI」)。 ↩↩ -
出处:「4 - Microservices」第 960–991 段(
text/09-ch04-4-microservices.txt:963,搜「hundreds or thousands of microservices」;:979搜「robust solution」)。 ↩↩ -
出处:「4 - Microservices」第 352–353 段(
text/09-ch04-4-microservices.txt:353,搜「two-pizza rule」)。 ↩ -
出处:「4 - Microservices」第 1017–1037 段(
text/09-ch04-4-microservices.txt:1027,搜「broader set of practices」)。 ↩ -
出处:「4 - Microservices」复习题(
text/09-ch04-4-microservices.txt:1074,搜「service mesh」;:1076搜「managing database transactions」)。 ↩↩ -
出处:「4 - Microservices」第 993–1015 段(
text/09-ch04-4-microservices.txt:996,搜「FastAPI and GraphQL」)。 ↩