—— 单体软件到微服务框架 · 架构进化路线 ——

架构进化之路

小哲的「轻记账」已经长成 100 人团队、500 万行代码的庞然大物——但它还是那个创业第一天写下的「单体应用」。发布要 2 小时、改一行代码全量回归、一个内存泄漏拖垮全站。周师傅说:该进化了。这一本,从单体到微服务,把架构演进的全路线走一遍——包括那些「其实不该拆」的警告。

🧱 📦 🧩 🧬 🔗 🗄️ 🐳 🔍 🕸️ 🗺️
序 章

巨石阵的崩溃

当「一个应用」变成「一座山」
🧑‍💻
小哲

师傅,出大事了!我们的「轻记账」现在 500 万行代码、100 个开发在同一个仓库里改——昨天发布等了 2 小时,凌晨上线后一个内存泄漏,全站瘫痪 40 分钟!老板说「必须拆微服务」,今天就要方案!

🧙
周师傅

冷静。先说最重要的一句话:「必须拆微服务」这句话本身就值得怀疑。架构不是越新越好,是「匹配当前阶段」最好。我先带你走一遍完整的进化路线,让你自己判断——你们到底该不该拆、怎么拆。

1
单体架构一切软件的开始——简单、快、好调试
2
模块化单体先分层、再分模块——单体的自我优化
3
单体的天花板什么时候必须拆:痛点清单 + 康威定律
4
微服务初识按业务域切分、DDD、独立部署独立扩展
5
服务通信REST/gRPC、消息队列、网关、服务发现
6
数据拆分独立数据库、Saga、最终一致——最难一关
7
部署运维Docker、K8s、滚动发布、弹性伸缩
8
可观测性日志/指标/链路追踪——微服务的眼睛
9
服务网格Istio、sidecar、云原生、Serverless
10
演进路线绞杀者模式、渐进拆分、避坑与反模式
🧙
周师傅

记住一句话:微服务不是银弹,是「用复杂度换灵活性」的交易——拆之前先想清楚,你现在的痛,微服务真能治吗?走,第一站,从最开始讲起。

第 1 站

单体架构:一切的起点

Monolith · 三层架构 · 部署单元

被吐槽最多的「单体」,其实是最伟大也最务实的架构——全世界 90% 的软件都是单体,而且大多数「就该是单体」。

🧙
周师傅

单体架构(Monolith):整个应用打成一个包、部署成一份——前端页面、业务逻辑、数据库访问全在一个进程里。经典形态是三层架构:表现层(页面/API)→ 业务层(逻辑)→ 数据层(数据库)。

你创业第一天写轻记账时,就是最标准的单体——而且那是当时唯一正确的选择:一个人、一个包、一个数据库,部署简单、调试直接、没有网络开销。

单体架构示意图
┌──────────────────────────────────┐
│          轻记账 单体应用            │
│  ┌──────────┐  ┌──────────────┐  │
│  │ 表现层    │  │ 业务层        │  │
│  │ 页面/API │→ │ 记账/用户/报表 │  │
│  └──────────┘  └──────┬───────┘  │
│  ┌────────────────────┴───────┐  │
│  │ 数据层:ORM + SQL           │  │
│  └──────────────────┬─────────┘  │
└─────────────────────┼────────────┘
                      ↓
              MySQL 数据库(单库)

一个部署包 → 一台/一组服务器 → 整体上线、整体回滚

【单体的优点(别急着嫌弃)】
  简单:一个仓库、一个部署、一个调试环境
  快:函数直接调用,没有网络开销(最最关键!)
  好测:一套测试环境全覆盖
  事务好做:一个数据库,ACID 随便用

【单体的缺点(长大后的痛)】
  代码耦合:改一行可能影响全局
  发布沉重:500 万行全量构建、全量回归
  扩展粗放:只能整体扩容(哪怕只有报表模块吃资源)
  技术锁定:换语言/框架?等于重写
应用场景:创业公司的「正确选择」

轻记账创业期:1 个后端、1 个前端、1 个数据库,单体应用两周上线——如果当时拆微服务,光服务间通信和部署环境就能拖死团队。单体不是「落后」,是「在那个阶段最正确」。

单体术语

  • 单体架构(Monolith):一个应用、一个部署单元、一个数据库。
  • 三层架构:表现层 / 业务层 / 数据层——单体的经典分层。
  • 部署单元:一次发布的最小单位——单体就是「整个应用」。
  • 耦合:模块间相互依赖的程度——单体的原罪。
  • 整体扩容:加机器只能整包复制——资源利用率低。

本站收获:单体 = 简单、快、好测——创业期的唯一正解。它的缺点只在「长大之后」才发作:耦合、发布重、扩容粗、锁技术。别骂单体,先问自己配不配得上它。

第 2 站

模块化:单体的自我优化

分层 · 模块化单体 · 依赖倒置 · 模块边界

拆微服务之前,先试试「拆模块」——一个部署单元里,把代码按业务切成边界清晰的模块。很多时候,这已经解决 80% 的痛点。

🧙
周师傅

模块化单体(Modular Monolith):还是打成一个包部署,但内部按业务模块严格分层、边界清晰——记账模块、用户模块、报表模块互不直接调内部类,只通过「定义好的接口」通信。

关键设计原则:依赖倒置(高层模块不依赖低层模块的实现,依赖抽象接口)、模块边界(禁止跨模块乱调)、接口隔离(对外只暴露该暴露的)。

它的好处:代码边界清晰 → 未来拆微服务时,模块就是现成的服务边界。它是「微服务的预备课」。

模块化单体 vs 一锅粥
❌ 传统单体(一锅粥):
  记账Service 直接 new 用户Dao、改报表的全局变量……
  → 谁也说不清边界,改一行怕三天

✅ 模块化单体(有边界):
  ┌─ 记账模块 ─┐   ┌─ 用户模块 ─┐   ┌─ 报表模块 ─┐
  │ 内部类私有  │   │ 内部类私有  │   │ 内部类私有  │
  │ 只暴露接口  │   │ 只暴露接口  │   │ 只暴露接口  │
  └─────┬──────┘   └─────┬──────┘   └─────┬──────┘
        └──────── 模块间只走接口 ──────────┘
  仍是一个部署包,但内部是「乐高积木」,不是「一锅粥」

【依赖倒置(DIP)】
  模块 A 需要模块 B 的能力 → 面向「B 的接口」编程
  → 换实现不影响 A,测试还能 mock(衔接第一本的概念)

【模块化单体的价值】
  代码边界 = 未来服务边界(拆分成本大降)
  编译/测试可以按模块增量(构建快了)
  新人接手看得懂(有地图了)
  —— 很多团队「想拆微服务」,其实拆到模块化就够了!
应用场景:先模块化,缓拆微服务

小哲团队花了 3 个月把 500 万行代码整理成 6 大模块(记账/用户/报表/账本/通知/管理后台),边界清晰后:构建从 2 小时降到 40 分钟、回归测试范围缩小、新人 1 周上手。老板问「微服务呢?」——周师傅答:先让模块化跑半年,让痛点点位现形,再决定拆哪个。

模块化术语

  • 模块化单体:一个部署单元 + 内部清晰模块边界——微服务的「预备课」。
  • 依赖倒置(DIP):面向接口编程,不面向实现——模块解耦的基石。
  • 接口隔离:只暴露该暴露的——「最少知识原则」。
  • 模块边界 = 服务边界:为将来拆分铺路。
  • 何时够用:团队 < 50 人、发布频率能接受 → 模块化单体常常就是终点。

本站收获:模块化单体 = 一个包 + 清晰边界 + 面向接口。它是性价比最高的「中间态」——很多团队的终点其实在这里,微服务是可选的下一个台阶,不是必经之路。

第 3 站

天花板:为什么必须拆

痛点清单 · 康威定律 · 爆炸半径

不是所有单体都要拆,但所有单体最终都会撞到「天花板」。这一站,列出「必须拆」的硬指标——用它们对照自己公司,别凭感觉。

🧙
周师傅

单体的天花板,通常由四根柱子撑到极限:

  • ① 团队协作:100 人改同一个仓库 → 合并冲突、互相踩脚。这背后有个铁律——康威定律:系统的架构,会复制组织的沟通结构。团队大了,单体必然被组织「逼」着拆。
  • ② 发布频率:发布一次 2 小时、全量回归、上线要审批——业务要求每天发 10 次,单体根本供不上。
  • ③ 扩展瓶颈:只有报表模块吃资源,却要整包扩容 10 台——浪费 90% 的钱。
  • ④ 爆炸半径:一个模块内存泄漏 → 全站瘫痪。单体里「一颗老鼠屎坏一锅粥」,没有隔离。
「该拆了」的体检表(对照打分)
【必须拆的硬指标(中 3 条以上才认真考虑)】
  □ 团队 > 50 人挤一个仓库,合并冲突天天有
  □ 发布一次 > 30 分钟,且要全量回归
  □ 业务要求独立发布频率(某模块一周发 5 次)
  □ 只有某个模块吃资源,却要整包扩容
  □ 一个模块故障拖垮全站(爆炸半径 = 全部)
  □ 尝试换技术栈(如某模块想用 Go 重写)被锁死
  □ 新人上手 > 1 个月还搞不清模块边界

【康威定律(Conway's Law)】
  「设计系统的组织,最终产生的架构,等同于组织的沟通结构」
  5 人团队 → 天然单体;5 个独立小组 → 自然长出 5 个服务
  → 拆微服务之前,先看团队怎么组织的!

【爆炸半径】
  单体:1 个模块炸 → 全站陪葬
  微服务:订单服务炸 → 支付服务还能活(有降级预案的话)

【反直觉提醒】
  痛点没到 → 拆了更痛(复杂度暴涨)
  痛点到了 → 不拆也痛(发布瘫痪)
  关键:用体检表打分,不要看别人拆就跟风
应用场景:小哲团队的体检结果

体检打分:100 人一仓库 ✅、发布 2 小时 ✅、报表模块拖垮全站 ✅、模块边界不清 ✅——四条硬指标全中!周师傅点头:你们是真的「该拆了」。但拆法不是「一次性大爆炸」,而是渐进式(第 10 站讲)。

天花板术语

  • 康威定律:组织沟通结构决定系统架构——拆服务先拆团队。
  • 爆炸半径:故障影响的扩散范围——微服务的核心价值之一。
  • 发布频率:业务需要独立发版的节奏——单体供不上就说明该拆。
  • 整包扩容 vs 按需扩容:单体的资源浪费点。
  • 技术栈锁定:单体换语言 = 重写——「用 Go 重写报表模块」的念头就是拆分信号。

本站收获:拆不拆看「体检表」:团队、发布、扩容、爆炸半径四条硬指标,中 3 条以上才认真考虑。别跟风——痛没到,拆了更痛;痛到了,不拆更痛。

第 4 站

微服务初识:按业务切分

微服务定义 · DDD · 限界上下文 · 拆分原则

微服务不是「把代码拆小」,是「按业务能力切分自治单元」——每个服务有自己的数据、自己的生命周期、自己的团队。这一站讲拆分的「哲学」。

🧙
周师傅

先给微服务下个准确定义——它不是「小单体」,而是:按业务能力拆分、独立部署、独立扩展、独立拥有数据的小型自治服务

拆分的「指南针」是 DDD(领域驱动设计):先按业务领域画地图——限界上下文(Bounded Context) 就是服务的天然边界。记账是一个上下文、用户是一个上下文、支付是一个上下文——每个上下文内聚、上下文间松耦合。

原则很简单:按「业务能力」拆,不按「技术层」拆——不是「前端服务/后端服务/数据库服务」,而是「订单服务/库存服务/支付服务」。

轻记账拆分为例:按业务域切
❌ 错误拆法(按技术层拆):
  表现服务 → 业务服务 → 数据服务(等于把单体竖切三刀,更乱!)

✅ 正确拆法(按业务能力拆):
  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
  │ 用户服务 │ │ 账本服务 │ │ 支付服务 │ │ 报表服务 │
  │ 用户/登录 │ │ 记账/分类 │ │ 支付/退款 │ │ 统计/分析 │
  └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘
       └──── 各自独立部署 · 各自独立数据库 ────┘

【DDD 核心概念】
  限界上下文:业务领域内「内聚的边界」(账本和支付是两个世界)
  领域模型:每个上下文内部的语言和规则
  聚合根:边界内的一致性入口(如「订单」聚合)
  → DDD 地图画清楚了,服务边界就出来了

【好服务的五条标准】
  独立部署:改它不影响别人(CI/CD 各自跑)
  独立扩展:报表吃资源,只扩报表
  独立故障:它挂了别人能降级活
  独立数据:数据库归它独有(关键!)
  独立团队:一个服务一个「小队」负责(康威定律)

微服务术语

  • 微服务(Microservices):按业务能力拆分、独立部署/扩展/拥有的自治服务。
  • DDD(领域驱动设计):按业务领域建模——微服务拆分的「地图学」。
  • 限界上下文:领域的内聚边界——服务边界的天然依据。
  • 聚合根:边界内一致性的入口(订单聚合)。
  • 独立五要素:部署/扩展/故障/数据/团队——缺一个都不算真微服务。
  • 反模式:分布式单体:拆了服务但数据共库、部署共发——假微服务,真灾难。

本站收获:微服务 = 按业务能力(DDD 限界上下文)切分的自治单元,独立部署/扩展/故障/数据/团队五要素缺一不可。别按技术层拆,别拆成分布式单体。

第 5 站

服务通信:怎么说话

REST/gRPC · 消息队列 · API 网关 · 服务发现 · 熔断

单体里函数直接调用;微服务里,调用要跨网络——这是最大的变化,也是最多的坑。服务间怎么说话,直接决定系统稳不稳。

🧙
周师傅

服务间通信两大流派:

  • 同步:A 调 B,等结果——REST(HTTP+JSON,通用简单)或 gRPC(高性能二进制,内部服务首选)。
  • 异步:A 发消息到队列,不等 B——消息队列(Kafka/RabbitMQ,第九本的老朋友),解耦 + 削峰。

光有通信协议还不够,四个「基础设施」必须配套:

  • API 网关:所有请求的统一入口——鉴权、限流、路由(服务对外的门卫)。
  • 服务发现:服务地址会变(扩容/重启)——注册中心(Nacos/Consul)让大家互相找得到。
  • 负载均衡:一个服务多个实例——谁闲谁干(衔接第二本)。
  • 容错三件套:超时、重试、熔断——B 挂了别把 A 拖死(熔断 = 快速失败 + 降级兜底)。
下单链路:跨 4 个服务的调用
用户点击「下单」
   ↓
API 网关(鉴权 + 限流 + 路由)
   ↓
订单服务 ──同步调用──→ 用户服务(查用户)
   ↓
订单服务 ──同步调用──→ 库存服务(扣库存)⚠️ 可能失败
   │ 失败怎么办?熔断器打开 → 快速失败 → 返回「库存不足」
   ↓
订单服务 ──异步发消息──→ Kafka
   ↓
通知服务(消费消息 → 发短信/推送)——不用等,异步解耦

【容错三件套(灵魂)】
  超时:等 3 秒没响应就当失败(别无限等)
  重试:短暂故障重试 2 次(但要小心雪崩!)
  熔断:连续失败 N 次 → 打开熔断器,直接快速失败
       → 给下游喘息时间,防止「故障雪崩」(衔接第七本)

【同步 vs 异步怎么选】
  需要结果马上用(查用户)→ 同步
  不急着要结果(发通知)→ 异步
  高并发削峰(订单洪峰)→ 异步队列
应用场景:库存服务挂了,订单还在

大促瞬间库存服务扛不住——如果同步硬等,订单服务跟着全挂,雪崩到全站。用了熔断 + 降级:库存服务超时 → 熔断器打开 → 订单服务直接返回「暂时拥挤,稍后再试」→ 用户服务、支付服务毫发无损。爆炸半径从「全站」缩小到「下单功能」。

通信术语

  • 同步 vs 异步:REST/gRPC 等结果 vs 消息队列不等——按需选择。
  • API 网关:统一入口:鉴权、限流、路由——服务的前台接待。
  • 服务发现 / 注册中心:服务互相找到对方的「通讯录」。
  • 熔断 / 降级 / 限流:容错三件套——微服务稳定性的命根子。
  • 故障雪崩:一个服务慢 → 拖垮调用方 → 连锁反应——必须用熔断切断。
  • gRPC vs REST:高性能二进制 vs 通用 HTTP——内部 vs 对外。

本站收获:服务通信 = 同步/异步两条路 + 网关/注册中心/负载均衡 + 超时重试熔断。微服务的第一课:调用是会失败的——把「失败」设计进系统,而不是祈祷它不发生。

第 6 站

数据拆分:最难的一关

独立数据库 · Saga · 最终一致 · CQRS · 事件溯源

微服务里最痛的坑不是代码,是数据——单体里一个事务搞定的事,拆开后变成「跨服务的分布式难题」。这一站讲清楚数据怎么拆、一致性怎么保。

🧙
周师傅

铁律第一条:每个服务独享自己的数据库——服务之间绝不能「共库」(共库 = 假微服务 = 分布式单体,改表结构牵一发动全身)。

但数据一拆,老问题来了:单体里「下单 + 扣库存 + 减余额」是一个本地事务,原子完成;拆开后跨三个库,怎么办?三个答案:

  • 两阶段提交(2PC):强一致但慢、脆弱——生产基本不用。
  • Saga 模式:把一个长事务拆成一系列本地事务 + 补偿——下单→扣库存→减余额,任何一步失败,执行「补偿」回滚前面(退款、加库存)。主流方案。
  • 最终一致:不追求「瞬间一致」,接受「过一会儿一致」——订单创建了但积分 5 秒后到账,用户无感。
Saga 模式:跨服务事务的「补偿舞蹈」
【正常流程】
  订单服务:创建订单 ✓ → 扣库存 ✓ → 扣款 ✓ → 完成!
  每一步都是独立本地事务(自己的库)

【失败流程(第 2 步扣库存失败)】
  订单服务:创建订单 ✓ → 扣库存 ✗
  → 启动补偿:
    补偿「取消订单」(回滚第 1 步)
  → 最终结果:数据回到原点,用户看到「下单失败」

【Saga 两种编排】
  编排式:中央 Saga 协调器指挥每一步(可控)
  协同式:服务间通过事件互相触发(解耦,但难追踪)

【最终一致的实践】
  消息队列 + 幂等消费:积分服务消费「订单创建」事件
  → 5 秒内到账;重复消费?幂等键去重(第九本老朋友)

【CQRS(读写分离)】
  写走订单库,读走报表库(事件同步过去)
  → 读写各自优化——报表服务不再拖累写链路

【事件溯源(Event Sourcing)】
  不存「当前状态」,只存「事件流」——状态由事件重放
  → 能回到任意历史状态(和第九本 Iceberg 时间旅行异曲同工)

数据拆分术语

  • 服务独享数据库:微服务铁律——共库 = 假微服务。
  • Saga 模式:本地事务链 + 补偿回滚——分布式事务的主流解。
  • 最终一致:不追求瞬间一致,接受短时不一致——大多数业务的现实答案。
  • 幂等性:同一消息消费 N 次结果一致——消息场景的保命符。
  • CQRS:读写分离——查询和命令各走各的路。
  • 事件溯源:只存事件流——状态可重放、可回溯。
  • 2PC:两阶段提交——教科书有,生产很少用。

本站收获:数据拆分 = 服务独享库 + Saga 补偿 + 最终一致 + 幂等消费。拆服务容易,拆数据难——跨库事务的答案不是「更强的事务」,而是「接受最终一致 + 设计好补偿」。

第 7 站

部署运维:容器与 K8s

Docker · Kubernetes · 滚动发布 · 弹性伸缩

单体一台服务器就够;微服务几十个服务、上百个实例——没有容器化和编排,运维会被活活累死。这一站,把部署问题讲透。

🧙
周师傅

微服务部署三板斧(都是前几本的老朋友,这里串成体系):

  • 容器化(Docker):每个服务打包成镜像——「环境固化」,在哪儿跑都一样(第六本讲过容器,这里用到极致)。
  • 编排(Kubernetes/K8s):几百个容器怎么调度、怎么伸缩、怎么自愈——Pod 是运行单元、Deployment 管副本、Service 管访问、HPA 自动伸缩。
  • 发布策略:滚动发布(一批批替换)、灰度发布(先 1% 用户试)——出问题随时回滚(第二本、第六本的 DevOps 技能在这里开花)。
K8s 部署微服务(概念图)
┌──────────────────── K8s 集群 ────────────────────┐
│  ┌─────┐ ┌─────┐ ┌─────┐     ┌─────┐ ┌─────┐    │
│  │订单 │ │订单 │ │订单 │ ...  │支付 │ │支付 │ ... │
│  │Pod  │ │Pod  │ │Pod  │     │Pod  │ │Pod  │    │
│  └──┬──┘ └──┬──┘ └──┬──┘     └──┬──┘ └──┬──┘    │
│     └──Service(订单)──┘          └─Service(支付)─┘ │
│   · Deployment:声明「要 3 个副本」,坏了自动补    │
│   · HPA:CPU 超 70% → 自动扩到 10 个              │
│   · Ingress:外部流量入口 → 路由到 Service         │
└──────────────────────────────────────────────────┘

【部署流程(DevOps 完整链)】
  git push → CI 构建镜像 → 推镜像仓库
  → CD 更新 Deployment → 滚动发布(一批批换,不中断)
  → 健康检查失败?自动回滚上一版
  (第二本《软件王国建造记》第 6 站的完整落地!)

【发布策略对比】
  滚动发布:一批批替换,始终有可用实例
  蓝绿部署:两套环境切流量(第六本讲过)
  灰度/金丝雀:1% 用户试新版,稳了再全量
  → 微服务时代:每个服务各自灰度,互不牵连

【K8s 学习要点】
  Pod(最小单元)/ Deployment(声明式管理)/ Service(访问入口)
  ConfigMap/Secret(配置与密钥)/ Ingress(网关)
应用场景:报表服务独立扩容

微服务化后:大促时只有报表服务吃资源——K8s HPA 自动把报表服务从 2 个实例扩到 15 个,其他服务纹丝不动;促销结束自动缩回 2 个。这就是「独立扩展」的威力——单体时代得整包扩 10 台,现在只扩需要的那一个。

部署术语

  • Docker 镜像:服务 + 环境打包——「哪儿跑都一样」。
  • Kubernetes(K8s):容器编排平台——Pod/Deployment/Service/HPA。
  • 滚动 / 蓝绿 / 灰度发布:三种发布策略——中断越少越好。
  • 弹性伸缩(HPA):按负载自动扩缩容——按需付费的基石。
  • 自愈:Pod 挂了自动重建——K8s 的「自我修复」。
  • ConfigMap/Secret:配置与密钥管理——微服务的「环境变量抽屉」。

本站收获:部署 = Docker 固化环境 + K8s 编排调度 + 滚动/灰度发布 + HPA 弹性伸缩。微服务的运维复杂度,全靠容器化 + 编排「压下去」——没有 K8s,几十个服务没法活。

第 8 站

可观测性:微服务的眼睛

日志 · 指标 · 链路追踪 · OpenTelemetry · SLO

单体排查问题:看一个应用的日志就行。微服务排查:一个请求跨 10 个服务——没有「眼睛」,故障来了只能靠猜。可观测性三支柱,微服务的标配。

🧙
周师傅

可观测性三大支柱:

  • 日志(Logs):所有服务日志集中收集(ELK/Loki)——出错能翻「案发现场」。
  • 指标(Metrics):每个服务的 QPS、延迟、错误率(Prometheus + Grafana)——状态一眼可见(衔接第七本监控)。
  • 链路追踪(Tracing):一个请求从网关到订单到库存的完整旅程——TraceID 串起所有服务的日志,SkyWalking/OpenTelemetry 是标配。故障慢在哪一跳,一目了然。

再加两个管理概念:SLO(服务等级目标)——「下单接口 P99 延迟 < 500ms」,达到与否是团队的 KPI;告警——SLO 被突破自动报警(第七本的老朋友)。

链路追踪:一个请求的「全程录像」
用户请求(TraceID: abc-123)
   ↓ 网关         span: 鉴权 2ms
   ↓ 订单服务      span: 创建订单 20ms
     ↓ 用户服务    span: 查用户 15ms      ← 这里慢了?!
     ↓ 库存服务    span: 扣库存 300ms     ← 找到瓶颈!
   ↓ 通知服务      span: 发消息 5ms(异步)

  TraceID 贯穿所有日志 → 按 ID 一搜,全程时间轴都在
  → 「请求慢」从玄学变成科学:P99 延迟、每跳耗时、瓶颈定位

【三支柱分工】
  日志:具体报错是什么(what happened)
  指标:系统整体状态如何(how is it going)
  追踪:单个请求经历了什么(where is the problem)

【技术选型】
  日志:ELK / Loki + Grafana
  指标:Prometheus + Grafana
  追踪:SkyWalking / OpenTelemetry + Jaeger/Tempo
  一体化:阿里云 ARMS / 腾讯云 APM(托管省事)

【SLO 与告警】
  SLO:目标(P99 延迟 < 500ms)
  SLI:实际测量值(当前 P99 = 800ms)
  告警:SLI 突破 SLO → 告警 → 值班(第七本联动)
应用场景:一次 5 分钟的「慢请求破案」

用户反馈「下单很慢」。单体时代:翻日志找半天;微服务时代:SkyWalking 打开链路追踪 → 发现 90% 时间卡在「库存服务」→ 点进去看到数据库慢查询 → 加索引 → 解决。全程 5 分钟——可观测性就是微服务时代的「破案工具」。

可观测性术语

  • 三支柱:日志(what)、指标(how)、追踪(where)——缺一不可。
  • TraceID / Span:一次请求的全局 ID / 每一跳的时间片段。
  • 分布式链路追踪:SkyWalking / OpenTelemetry——跨服务排障神器。
  • SLO / SLI:服务目标 / 实际表现——把「稳不稳」变成数字。
  • 集中日志 / 指标平台:ELK + Prometheus + Grafana——微服务标配三件套。
  • 告警与值班:SLO 被突破自动告警——可观测性的「最后出口」。

本站收获:可观测性 = 日志(what)+ 指标(how)+ 追踪(where)+ SLO(目标)。微服务没有眼睛就是瞎子——这四样配齐,故障从「猜」变成「查」。

第 9 站

服务网格:云原生进阶

Service Mesh · Sidecar · 云原生 12 要素 · Serverless

微服务越拆越多,熔断、限流、重试这些「公共能力」在每个服务里重复实现——太烦了。服务网格把这些能力从代码里「抽出来」,下沉到基础设施层。

🧙
周师傅

服务网格(Service Mesh)的核心思想:把「服务间通信的通用能力」(熔断、限流、重试、鉴权、链路追踪)从业务代码里剥离出来,用轻量代理(Sidecar)在每个服务旁边实现——业务代码只关心业务,通信能力统一由 数据面(Sidecar 们)执行、控制面(如 Istio)下发策略。

它带来的进化:流量治理从「代码」变成了「配置」——想给支付服务加限流?控制台改一行 YAML 下发,不用改任何代码、不用发版。

再往上,就是 云原生:12 要素(配置外置、无状态、日志流式……)+ K8s + 容器——以及 Serverless(FaaS):连服务器都不用管了,按调用付费。

服务网格架构
┌──────────── 控制面(Istio)────────────┐
│ 策略下发:熔断/限流/重试/鉴权/流量比例   │
└──────┬───────────────────────────┬──────┘
       │ 下发配置                    │
  ┌────┴────┐    ┌────┴────┐    ┌────┴────┐
  │订单服务  │    │支付服务  │    │库存服务  │
  │ +Sidecar │    │ +Sidecar │    │ +Sidecar │  ← 数据面
  └────┬────┘    └────┬────┘    └────┬────┘
       所有流量都走 Sidecar(透明代理)

【优点】
  流量治理不写代码:改配置即生效(灰度 10% 流量,一行 YAML)
  可观测增强:Sidecar 自动上报全链路追踪
  多语言统一:Java/Go/Python 服务用同一套治理能力

【代价(诚实说)】
  性能损耗:每个请求多一跳代理(几毫秒)
  复杂度转移:把「代码复杂度」换成了「运维复杂度」
  → 服务少(<30 个)时,服务网格是过度设计!

【云原生 12 要素(速览)】
  配置外置 / 无状态 / 日志流式 / 开发生产一致
  / 依赖显式声明 / 进程无共享……(网上有完整清单)

【Serverless / FaaS】
  连容器都不用管:写个函数,平台自动跑
  极致弹性:按调用次数付费,冷启动有延迟
  适合:任务型/事件驱动型(消息处理、图片处理)

进阶术语

  • 服务网格(Service Mesh):通信能力下沉到 Sidecar——熔断限流不写代码。
  • Sidecar 代理:服务旁边的「交通协管」——数据面。
  • 控制面 / 数据面:策略大脑 / 执行代理——Istio 是代表。
  • 云原生 12 要素:云上应用的最佳实践清单。
  • Serverless(FaaS):连服务器都不用管——按调用付费。
  • 适度原则:服务少时别上服务网格——技术选型要匹配规模。

本站收获:服务网格 = 把熔断限流从代码里抽到 Sidecar——改配置即治理。云原生 = 12 要素 + K8s + Serverless。但记住:规模不到,别硬上——高级架构是给「需要的人」准备的。

第 10 站

演进路线:拆分的艺术

绞杀者模式 · 渐进式拆分 · 避坑 · 什么时候不该拆

最后一站,把整条进化路线串成「实操地图」——怎么从 500 万行单体安全地走到微服务,以及最重要的:哪些坑是前人用命踩出来的。

🧙
周师傅

核心心法八个字:渐进式拆分,绝不重写。「把单体推倒重写微服务」是行业最大灾难——重写两年,业务停了,团队崩了,最后发现旧系统还能用。

正确姿势是 绞杀者模式(Strangler Pattern):像藤蔓慢慢绞杀老树——每次只切一个模块出来变成服务,老的照常跑,新的慢慢接管。切一块、稳一块、再切下一块。

绞杀者模式:拆分的实操路线
【阶段一:模块化(3 个月)】
  单体内部先划清模块边界(第 2 站)→ 为拆分铺路

【阶段二:第一个服务(优先选「低耦合高价值」)】
  先拆哪个?打分:
  · 业务独立性强(报表模块 —— 只读,不参与写链路)
  · 吃资源大户(单独扩容收益最大)
  · 团队边界清晰(谁负责谁拆)
  → 报表模块 → 报表服务(独立部署+独立库+独立团队)

【阶段三:绞杀循环(持续)】
  每 1-2 个月绞杀一个模块:
  切接口 → 迁移数据 → 切流量 → 删老代码
  → 老单体越来越瘦,新服务越来越多
  → 每一步都可回滚,业务零中断

【血泪避坑清单(前人踩出来的)】
  ✗ 一次性大爆炸重构(灾难)
  ✗ 拆成「分布式单体」(共库共发布 = 假微服务)
  ✗ 每个服务各自为政(统一规范:网关/日志/追踪要统一)
  ✗ 忘记数据迁移(服务拆了,库没拆 = 白拆)
  ✗ 团队没跟上(拆服务先拆组织,康威定律!)

【什么时候不该拆(诚实建议)】
  团队 < 30 人 / 发布不频繁 / 单体还没乱 → 别拆!
  先把单体整理好(模块化)就是进步——不是所有公司都需要微服务
应用场景:轻记账的 12 个月演进实录

第 1-3 月:单体模块化(6 大模块边界清晰);第 4 月:拆出报表服务(吃资源大户,独立扩容);第 6 月:拆出用户服务(独立团队接手);第 9 月:拆出账本服务(数据迁移用了双写过渡);第 12 月:支付链路重构为 Saga。老单体从 500 万行瘦到 120 万行——发布从 2 小时到 15 分钟,爆炸半径从「全站」到「单服务」。

演进术语

  • 绞杀者模式(Strangler):渐进式拆分——藤蔓绞杀老树,一步一块。
  • 渐进式 vs 大爆炸:持续演进 vs 推倒重写——前者是工程,后者是赌博。
  • 双写过渡:数据迁移期间新旧库同时写——平滑切换的标配。
  • 统一规范:网关/日志/追踪/部署标准统一——防「万国牌」。
  • 拆分优先级:低耦合 + 高价值 + 团队清晰——先拆软柿子。
  • 反模式:分布式单体:假微服务——比真单体还难维护。
  • 规模匹配:人少就别拆——模块化可能就是终点。

本站收获:演进 = 先模块化 → 绞杀者模式渐进拆分 → 统一规范 + 数据迁移跟上。拆分是艺术不是技术:宁可慢,不要断;规模不到,别硬拆——「渐进式拆分,绝不重写」。

附录

架构对比总表 + 路线图

最后一页:选型决策表

三大架构对比

维度单体模块化单体微服务
部署单元1 个1 个(内部模块化)N 个独立
团队规模适配< 20 人< 50 人50 人+(按服务分队)
发布频率低(周/月)中(天)高(每天多次)
扩展粒度整包扩容整包扩容按服务独立扩
故障影响全站全站(模块内可控)单服务(可降级)
事务处理本地事务(简单)本地事务(简单)Saga/最终一致(复杂)
排障难度高(需可观测性)
运维成本高(K8s/网格)
适合阶段创业期成长期规模化期
单体 简单快
模块化 划边界
体检 痛够不够
首拆 低耦合高价值
绞杀 逐个迁移
配套 通信/数据/部署
进阶 可观测/网格/云原生 🚀

一句话决策口诀

  • 团队小、发布少 → 单体(别折腾)
  • 团队中、有点乱 → 模块化单体(性价比最高)
  • 团队大、发布频、爆炸半径受不了 → 微服务(按绞杀者模式走)
  • 微服务已经很顺 → 考虑 服务网格/云原生(规模到了才上)
微服务不是银弹,
是「用复杂度换灵活性」的交易。
架构不是越新越好,是「匹配当前阶段」最好——
单体无罪,模块化够用就别拆;
真要拆,就学绞杀者:渐进式拆分,绝不重写;
而所有架构进化的终点,都是同一个词——适配。
🧱 📦 🧩 🧬 🔗 🗄️ 🐳 🔍 🕸️ 🗺️ 🌳
✌ 语言