课程目录

第 4 周 · 初阶

第4周:中间件与分布式

掌握分布式系统核心中间件

周目标:掌握消息队列、缓存、数据库等中间件

课程成果:CO1 CO2 CO8

已学习 0 / 7 天

本周 7 个学习日

Day 22

关系型数据库

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

把关系型数据库看成由连接与解析层、优化器和存储引擎组成的分层系统。InnoDB 的主键是聚簇索引,行数据就存放在主键 B+ 树的叶子上;二级索引叶子存的是主键值,因此不能被索引覆盖的查询需要回表。ACID 中的隔离性由四个隔离级别与 MVCC、行锁、间隙锁共同实现,脏读、不可重复读和幻读分别在不同级别被挡住。分库分表能缓解单机容量与写入压力,但会引入跨分片查询、全局主键和数据迁移等新成本,只有在有实测证据时才应该讨论。

听书与视频

本日听书

7 分钟 · MP3 · 双主持人讲解

B 站讲解

SQL入门教程 第01集 关系型数据库

_不剪发的Tony老师_ · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能画出一次 SELECT 从连接层、优化器到存储引擎的处理路径,并说明各层能观察到什么
  • 能解释聚簇索引与二级索引的存储差异,并用最左前缀、回表和覆盖索引判断一个索引是否会被用上
  • 能把脏读、不可重复读、幻读分别对应到隔离级别,并说明行锁与间隙锁在其中的作用
  • 能读懂 EXPLAIN 的 type、key、rows、Extra 字段,并把结论绑定到表结构、数据量和 MySQL 版本

核心讲解

索引不是「加了就快」

InnoDB 以主键组织表:主键 B+ 树的叶子节点直接保存整行数据,这就是聚簇索引;二级索引的叶子只保存索引列和主键值。因此用二级索引查询时,若需要的列不在索引里,就要拿主键再回到聚簇索引取一次数据,这一步叫回表。当查询需要的列全部包含在某个二级索引中时可以避免回表,官方文档称之为覆盖索引。理解这一点,才能解释为什么给同一张表加不同顺序的联合索引,性能差别可以很大。

联合索引按最左前缀匹配:索引 (a, b, c) 能支持 a、a+b、a+b+c 的等值查找,但单独用 b 或 c 过滤时通常无法有效利用。范围条件之后的列一般也不能继续用于精确定位。索引还有写入代价——每次插入、更新、删除都要维护对应的 B+ 树,索引越多写放大越明显。所以「加索引」是一次权衡,不是无条件的优化,必须用具体查询和具体数据量来验证。

事务、隔离级别与锁

MySQL 的 InnoDB 支持 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE 四个隔离级别,默认是 REPEATABLE READ。级别越高,能避免的异常越多,并发代价通常也越大:READ COMMITTED 消除脏读,REPEATABLE READ 让同一事务内的一致性读看到同一份快照,SERIALIZABLE 则把普通读也变成加锁读。学习者应把「哪个异常在哪个级别被挡住」写成一张对照表,而不是死记级别名称。

锁的粒度决定了并发冲突的形状。InnoDB 的行锁作用在索引记录上——这意味着如果一条 UPDATE 没有走索引,可能会锁住远超预期的范围。间隙锁与临键锁用于阻止范围内插入,从而抑制幻读,但也更容易造成阻塞。死锁通常来自两个事务以相反顺序获取同一组资源;处理方式是统一访问顺序、缩短事务、必要时重试,而不是简单地调大超时。

实践任务

在本人授权的本地 MySQL 实例中构造一张有数据的测试表,用 EXPLAIN 对比命中索引、回表和全表扫描三种执行计划,并记录版本、表结构、行数与原始输出。

  • 在本人授权的本地实例中创建一个专用测试库和随机后缀表名,插入至少十万行可复现的伪造数据,记录 MySQL 版本、表结构与行数。
  • 对同一个查询分别在无索引、有二级索引但需回表、有覆盖索引三种情况下执行 EXPLAIN,保存三份原始输出,重点对比 type、key、rows 和 Extra。
  • 写一条会退化为全表扫描的查询(例如在索引列上使用函数或以通配符开头的 LIKE),用 EXPLAIN 证明它没有用上索引,并解释原因。
  • 把三组观察整理成结论,明确标出哪些是本次实验条件下的事实、哪些是推断;实验结束后删除本人创建的测试库并记录删除结果。

自测与答案

第 1 题

同一张表上,为什么把查询需要的列都放进二级索引后,执行计划可能从「回表」变成「覆盖索引」?这样做的代价是什么?

尚未检查本题。

查看答案与评价要点

参考答案:二级索引叶子只存索引列和主键值,缺少的列必须回到聚簇索引再取一次;把所需列都放进索引后,查询可以只扫描该二级索引即可返回结果,从而免去回表。代价是索引变宽、占用更多空间,并增加每次写入时的索引维护开销。

评价要点:说明二级索引叶子存的是索引列与主键值;解释回表的触发条件和覆盖索引如何避免它;指出空间与写放大方面的代价

第 2 题

一条 UPDATE 语句在测试环境运行正常,上线后却频繁引起阻塞。从索引与锁的角度,应该优先检查什么?

尚未检查本题。

查看答案与评价要点

参考答案:优先检查 WHERE 条件是否走了索引:InnoDB 的行锁加在索引记录上,未命中索引时可能锁定远超预期的范围。还应检查隔离级别下是否产生间隙锁、事务是否过长、是否与其他事务以相反顺序访问同一批行。

评价要点:指出行锁作用在索引记录上;把未命中索引与锁范围扩大联系起来;提出事务长度、间隙锁或访问顺序中的至少一项排查方向

尚未完成自测。

今日完成标准

  • 提交三份 EXPLAIN 原始输出,并逐份说明 type、key、rows、Extra 反映了哪种访问路径
  • 用自己的话写出聚簇索引、二级索引、回表和覆盖索引的关系,并给出一个会失效的联合索引例子
  • 实验记录包含 MySQL 版本、表结构、数据量和清理结果,结论区分事实与推断

常见错误与纠正提示

  • 认为「建了索引就一定会用」,忽略最左前缀、函数包裹列和前导通配符会让索引失效
  • 把隔离级别当成性能开关随意调低,却没有说明放开了哪一类读异常
  • 只看查询耗时不看执行计划,把一次缓存命中的快速响应当作索引生效的证据

分层任务

基础任务

使用教师提供的建表脚本与数据集,完成三份 EXPLAIN 对比并口述每份计划走了哪条路径。

标准任务

自行设计数据与查询,完成三份 EXPLAIN 对比,并额外给出一个索引失效的反例与原因分析。

挑战任务

在同一张表上设计两条会互相死锁的事务,记录 SHOW ENGINE INNODB STATUS 的死锁信息,并提出一种消除死锁的访问顺序方案。

关联知识点

延伸阅读

学习状态:未学习

Day 23

NoSQL 与缓存

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

Redis 与 MongoDB 解决的是关系型数据库不擅长的问题,但各自有明确边界。Redis 的价值来自数据结构本身:字符串、哈希、列表、集合、有序集合和位图分别对应不同访问模式,排行榜用有序集合、去重用集合、会话用哈希;它的命令在单线程事件循环中执行,因此一条慢命令或一个超大 key 会阻塞整个实例。MongoDB 的核心决策是内嵌还是引用,以及写关注级别要不要等待多数节点确认。缓存部分的难点不是「加缓存」,而是一致性:更新顺序、穿透、击穿、雪崩各有不同成因和不同缓解手段。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

NoSQL数据库 键值数据库,列族数据库,文档数据库,图数据库

专升本计算机皮皮虾 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能为排行榜、去重、会话、计数、消息队列等场景各选出合适的 Redis 数据结构并说明理由
  • 能解释 Redis 单线程执行模型如何把大 key 与慢命令放大成实例级延迟
  • 能在 MongoDB 中判断一份数据应当内嵌还是引用,并说明写关注级别对持久性的影响
  • 能区分缓存穿透、击穿、雪崩的成因,并为每种情况给出一个可验证的缓解手段

核心讲解

选对数据结构,比选对产品更重要

Redis 的官方文档把数据类型作为第一层概念:有序集合按分数排序并支持按排名或分数范围取区间,天然适合排行榜;集合支持成员唯一与集合运算,适合去重和标签交并;哈希适合存放对象的多个字段而不必整体序列化;位图与 HyperLogLog 用极小的空间回答「是否出现过」和「大约有多少个不同值」。选错结构会把 O(log n) 的操作退化成一次全量读取再在应用里排序。

Redis 处理命令的主线程是单线程的,这带来了简单的原子语义,也意味着任何一条长时间运行的命令都会让其他请求排队。官方的延迟排查文档明确把慢命令、大 key、持久化 fork、内存交换列为常见来源。因此实践中要避免对大集合执行无界的范围操作,避免用 KEYS 扫描生产实例,并为 key 的大小和元素数量设定可检查的上界。

缓存一致性的三类失败

旁路缓存是最常见的模式:读时先查缓存,未命中则查数据库并回填;写时更新数据库并使缓存失效。更新顺序很重要——先删缓存再写库,或先写库再删缓存,在并发下都有可能出现短暂的旧值窗口,需要用过期时间兜底。真正要写进设计文档的,是「不一致窗口有多长、期间用户会看到什么、如何收敛」,而不是宣称缓存与数据库始终一致。

缓存穿透指查询一个数据库中也不存在的 key,缓存永远无法命中,请求全部打到数据库,可以用空值缓存或布隆过滤器缓解;缓存击穿指某个热点 key 过期瞬间大量并发同时回源,可以用互斥重建或逻辑过期缓解;缓存雪崩指大批 key 在同一时刻集中过期,缓解手段是给过期时间加随机抖动并分散预热。三者成因不同,混为一谈会导致用错手段。

实践任务

用本人本地的 Redis 实例实现一个带过期时间的排行榜与一段旁路缓存逻辑,构造缓存未命中、缓存穿透和批量同时过期三种情况并记录观察。

  • 在本人授权的本地 Redis 中用带随机前缀的 key 建立一个有序集合排行榜,写入若干成员与分数,用按排名取区间的命令验证结果顺序。
  • 实现一段旁路缓存读写逻辑:读未命中时回填并设置过期时间,写操作后使缓存失效;记录一次未命中和一次命中的完整调用序列。
  • 构造缓存穿透:反复查询一个数据库中不存在的 key,观察回源次数;再加入空值缓存后重复实验并对比。
  • 把一批 key 设置为同一过期时刻,观察集中过期后的回源峰值;改为过期时间加随机抖动后重复,记录两次差异并清理本次实验创建的所有 key。

自测与答案

第 1 题

为什么在 Redis 中「一个超大 key」会成为整个实例的可用性风险,而不只是这一个 key 变慢?

尚未检查本题。

查看答案与评价要点

参考答案:Redis 主线程按顺序执行命令,对超大 key 的操作会长时间占用主线程,期间其他客户端的请求只能排队,表现为整个实例的延迟升高;删除或序列化超大 key 时同样如此。因此需要限制单 key 的大小与元素数量,并避免无界范围操作。

评价要点:指出命令在主线程中顺序执行;说明长命令会让其他请求排队,影响面是实例级;给出限制 key 大小或避免无界操作的应对

第 2 题

缓存穿透与缓存雪崩的成因分别是什么?各应采用什么缓解手段?

尚未检查本题。

查看答案与评价要点

参考答案:穿透是查询数据库中本就不存在的数据,缓存永远不命中,请求全部落到数据库,可用空值缓存或布隆过滤器拦截;雪崩是大批 key 在同一时刻集中过期或缓存整体不可用,导致回源流量骤增,可用过期时间随机抖动、分散预热和限流降级缓解。

评价要点:准确区分两者成因;为穿透给出空值缓存或布隆过滤器;为雪崩给出抖动、预热或限流中的至少一项

尚未完成自测。

今日完成标准

  • 提交排行榜与旁路缓存的可复现操作记录,包含 Redis 版本、命令序列和原始返回
  • 用实验数据说明穿透与集中过期两种情况下回源次数的变化,并解释缓解手段为何有效
  • 写出本次实现中不一致窗口出现的位置与最长持续时间的估计,并标明这是推断还是实测

常见错误与纠正提示

  • 把 Redis 当成「更快的数据库」直接存放需要强持久性的业务主数据,却没有评估丢失窗口
  • 用一句「加缓存」概括方案,不说明失效策略、过期时间和不一致窗口
  • 在生产实例上用 KEYS 或无界范围命令做排查,把排查动作本身变成故障

分层任务

基础任务

使用教师提供的脚本完成排行榜与一次缓存命中/未命中的观察,并说出各自用了哪种数据结构。

标准任务

自行实现排行榜与旁路缓存,完成穿透与集中过期两组对比实验并提交记录。

挑战任务

为热点 key 实现互斥重建或逻辑过期方案,用并发请求验证回源次数下降,并分析该方案引入的新等待。

关联知识点

延伸阅读

学习状态:未学习

Day 24

消息队列

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

消息队列把同步调用变成异步事件,但也把「调用失败」变成了「投递语义」问题。Kafka 以分区为并行单位,每个分区是一个有序、可重放的提交日志,消费者组通过位点提交决定进度;顺序保证只在分区内成立。RabbitMQ 用交换机、绑定和队列描述路由,直连、主题、扇出等交换机类型对应不同分发模式。至少一次、至多一次、恰好一次都有成立条件:只要存在重试,消费端就必须自己做幂等。设计时要同时画出重复投递、消费失败、积压和死信这四条失败路径,而不是只画正常流程。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

消息队列Kafka是什么?架构是怎么样的?5分钟快速入门

小白debug · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能解释 Kafka 的分区、副本、消费者组和位点如何共同决定并行度与顺序保证的边界
  • 能用交换机、绑定、路由键描述 RabbitMQ 的一次消息分发,并说明它与 Kafka 模型的差异
  • 能判断一个消费流程属于至少一次还是至多一次,并说明恰好一次的成立条件
  • 能为重复投递、消费失败、积压、死信四条失败路径各写出一个可执行的处置动作

核心讲解

分区、位点与顺序的边界

Kafka 的主题被划分为多个分区,每个分区是一个只追加的有序日志,消息在分区内有严格顺序,跨分区则没有全局顺序。生产者通过分区键决定消息落到哪个分区——把同一订单的所有事件用订单号作为分区键,才能保证这些事件被顺序消费。消费者组中,一个分区在同一时刻只会被组内一个消费者消费,所以消费并行度的上限就是分区数,加消费者并不能突破这个上限。

消费进度由位点表示。位点在处理之前提交,崩溃时消息会丢失,接近至多一次;在处理之后提交,崩溃时消息会被重复消费,接近至少一次。Kafka 官方文档在讨论投递语义时明确指出,端到端的恰好一次需要生产端幂等、事务写入与消费端配合共同成立,而不是打开一个开关就能获得。这也是为什么消费端幂等必须由业务侧承担:用业务唯一键去重,比依赖中间件承诺更可靠。

两种模型与四条失败路径

RabbitMQ 遵循 AMQP 0-9-1 模型:生产者把消息发给交换机,交换机按绑定关系和路由键把消息投递到队列,消费者从队列取用。直连交换机按精确路由键匹配,主题交换机按模式匹配,扇出交换机广播给所有绑定队列。与 Kafka 的「日志可重放」不同,队列中的消息一旦被确认通常就移除了,重放需要额外设计。选型时要问的是:需要历史重放吗?需要多消费者各自独立读取同一份数据吗?

任何异步设计都要显式回答四个问题。重复投递:消费端如何用幂等键去重?消费失败:重试几次、退避多久、超过阈值后进入哪个死信队列?积压:如何观测滞后量、扩容是否受分区数限制、能否临时丢弃低价值消息?死信:谁负责查看、如何重投、重投是否会造成二次影响?把这四条写进设计文档,比画一张漂亮的正常流程图有价值得多。

实践任务

为一个订单事件设计可重放的消费流程,说明分区键、位点提交时机、幂等键与死信处理,并用本地实例或教师证据包验证重复投递时的结果。

  • 为订单事件选定分区键并说明理由,画出生产者、分区、消费者组和位点提交时机的关系图。
  • 定义幂等键与去重存储,写出消费端处理伪代码,明确「先处理后提交位点」还是「先提交后处理」以及对应的语义。
  • 在本地实例或教师证据包中人为重复投递同一条消息,记录去重前后的业务结果差异与原始日志。
  • 设计重试与死信策略:写明最大重试次数、退避方式、死信队列名称、告警条件与重投前的人工检查项。

自测与答案

第 1 题

为什么给 Kafka 消费者组增加消费者,超过分区数之后吞吐不再提升?

尚未检查本题。

查看答案与评价要点

参考答案:同一个分区在同一时刻只会分配给消费者组内的一个消费者,因此组内的有效并行度上限等于分区数;超出部分的消费者会处于空闲状态。要提升并行度需要增加分区,并同时评估分区键分布和顺序保证的影响。

评价要点:指出一个分区同时只被组内一个消费者消费;说明并行度上限由分区数决定;提出增加分区并考虑分区键或顺序影响

第 2 题

某系统声称使用了「恰好一次」的消息队列,因此消费端不做幂等。这个判断有什么问题?

尚未检查本题。

查看答案与评价要点

参考答案:恰好一次是端到端的性质,需要生产端幂等/事务、中间件配置和消费端处理与位点提交在同一原子边界内共同成立;一旦消费端有外部副作用(如调用第三方接口、写另一个库),中间件的承诺无法覆盖。因此消费端仍需用业务唯一键做幂等,否则重试会造成重复副作用。

评价要点:指出恰好一次是端到端条件而非中间件开关;说明外部副作用不在中间件事务边界内;坚持消费端用业务唯一键幂等

尚未完成自测。

今日完成标准

  • 提交包含分区键、位点提交时机、幂等键和死信路径的事件消费设计图
  • 用重复投递实验的原始记录证明幂等逻辑生效,并说明去重存储的过期策略
  • 为重试次数、退避时间和死信告警各给出具体数值,并说明这些数值的依据是实测还是假设

常见错误与纠正提示

  • 只画正常流程图,不写重复、失败、积压和死信这四条路径的处置动作
  • 把消息队列当成「异步就一定更可靠」,忽略积压时延迟会以另一种形式暴露给用户
  • 依赖中间件的投递语义承诺而不做业务幂等,重试时造成重复扣款或重复发货

分层任务

基础任务

使用教师证据包分析一份已有的消费日志,标出重复投递发生的位置与幂等键的作用。

标准任务

独立完成事件消费设计并在本地实例中验证重复投递被正确去重。

挑战任务

为一个跨两个下游系统的消费流程设计部分失败后的补偿方案,并说明为什么补偿动作也必须幂等。

关联知识点

延伸阅读

学习状态:未学习

Day 25

CAP 与一致性

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

CAP 讨论的是网络分区真实发生时,系统在一致性与可用性之间必须做出的取舍,而不是平时可以任选两项。把它与 PACELC 一起看才完整:没有分区时,延迟同样是要付的代价。真正影响设计的是一致性模型的层次——线性一致性、顺序一致性、因果一致性、最终一致性对客户端的可见性承诺各不相同,Jepsen 的一致性模型索引把它们的强弱关系整理成了可查的谱系。落到订单场景,需要回答的是:哪些数据必须强一致,哪些可以接受收敛窗口,收敛期间界面显示什么,以及如何对账。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

cap 视频教程(一)

zlzforever · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能准确陈述 CAP 的前提是网络分区已经发生,并说明「三选二」这一通俗表述的误导之处
  • 能用 PACELC 解释无分区时延迟与一致性之间的取舍
  • 能按强弱顺序排列线性一致性、因果一致性和最终一致性,并说明各自对客户端的承诺
  • 能为一个业务场景逐项指定一致性要求,并写出收敛窗口内的界面表现与对账方案

核心讲解

CAP 的前提常被省略

CAP 的完整表述是:在发生网络分区的情况下,分布式系统只能在一致性与可用性之间选择其一。它不是说平时可以在三者中任选两项,也不是说 CP 系统就一定比 AP 系统「更正确」。当分区没有发生时,一个系统完全可以同时提供强一致与高可用;真正被约束的是分区期间的行为:要么拒绝服务以保持一致,要么继续服务并接受可能返回旧值。

PACELC 补上了另一半:如果发生分区(P),在可用性(A)与一致性(C)之间选择;否则(E),在延迟(L)与一致性(C)之间选择。这解释了为什么很多系统在没有任何故障的日常运行中也会选择较弱的一致性——等待多数节点确认需要额外的往返时间。写设计文档时,把「分区时怎么办」和「无分区时愿意为一致性付多少延迟」分成两个问题回答,比争论系统属于 CP 还是 AP 更有用。

从一致性模型到业务边界

线性一致性要求每个操作看起来在其调用与返回之间的某一瞬间原子生效,且全局存在一个与实时顺序一致的总序,这是最强也最贵的承诺。顺序一致性放弃了与真实时间的对齐,因果一致性只保证有因果关系的操作被所有节点按相同顺序看到,最终一致性则只承诺在停止写入后系统最终收敛。Jepsen 的一致性模型索引把这些模型的包含关系整理成图,可用来核对自己的表述是否准确。

工程上很少有系统需要全局线性一致。订单场景可以逐项拆分:库存扣减通常需要强一致以避免超卖;支付状态需要以支付渠道的回调为准并保证幂等;订单列表的展示可以接受秒级收敛;运营统计接受分钟级甚至小时级延迟。为每一项写清楚要求之后,还要回答收敛期间界面显示什么——是显示「处理中」,还是显示可能过期的旧值,以及最终如何通过对账发现并修复不一致。

实践任务

为一个订单场景画出一致性边界:逐项标注库存、支付、订单状态、物流和统计各自要求的一致性级别、可接受的收敛窗口与对账机制。

  • 列出订单场景中的五类数据:库存、支付状态、订单状态、物流轨迹、运营统计,逐项写出业务上不可接受的错误现象。
  • 为每一项指定一致性要求,并从 Jepsen 一致性模型索引中选出对应的模型名称,避免使用「强一致」「弱一致」这类含糊表述。
  • 对可以接受最终一致的项,写出收敛窗口的估计值、窗口内的界面表现,以及用户在窗口内重复操作时的处理方式。
  • 为至少两项设计对账机制:对账数据来源、对账周期、发现不一致后的修复动作和人工介入条件;标明哪些数值是实测、哪些是假设。

自测与答案

第 1 题

「我们的系统选择了 AP,所以不需要考虑一致性」——这句话错在哪里?

尚未检查本题。

查看答案与评价要点

参考答案:CAP 只约束网络分区期间的取舍,AP 意味着分区时继续提供服务并可能返回旧值,而不是放弃一致性目标。系统仍需定义收敛模型(如最终一致或因果一致)、收敛窗口、窗口内的用户可见行为以及分区恢复后的冲突解决与对账机制。

评价要点:指出 CAP 的前提是分区已发生;说明 AP 仍需要明确的收敛模型与窗口;提出冲突解决或对账机制

第 2 题

在没有任何网络故障的日常运行中,一个跨机房数据库为什么仍可能选择较弱的一致性?

尚未检查本题。

查看答案与评价要点

参考答案:按 PACELC 的表述,无分区时系统在延迟与一致性之间取舍:跨机房的强一致写入需要等待远端多数节点确认,往返时延会直接体现在响应时间上。为满足延迟目标,系统可能选择本地确认加异步复制,代价是存在可见的收敛窗口。

评价要点:引用 PACELC 中无分区时的 L 与 C 取舍;说明跨机房确认带来的往返延迟;指出代价是收敛窗口或可能读到旧值

尚未完成自测。

今日完成标准

  • 提交一致性边界表,五类数据逐项给出一致性模型名称、收敛窗口与不可接受的错误现象
  • 至少两项配有可执行的对账方案,包含数据来源、周期与修复动作
  • 文档中区分事实、推断与待验证假设,收敛窗口数值标明来源

常见错误与纠正提示

  • 把 CAP 表述成「三选二」,据此声称系统「放弃了一致性」
  • 对整个系统只给一个笼统的一致性级别,不按数据项拆分
  • 承诺最终一致却不定义收敛窗口、界面表现和对账方式,出问题时无法判断是否异常

分层任务

基础任务

使用教师给出的订单数据清单,为每一项从候选一致性模型中选择并说明理由。

标准任务

独立完成五类数据的一致性边界表,并为两项设计对账机制。

挑战任务

为跨机房部署补充一份分区演练方案:写明注入方式、期望现象、判定标准和恢复后的一致性校验步骤。

关联知识点

延伸阅读

学习状态:未学习

Day 26

分布式事务

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

跨服务的一致性没有免费方案,只有代价不同的方案。两阶段提交依赖协调者投票,语义清晰但在协调者故障时参与者可能长时间持锁阻塞,跨服务长事务代价很高。TCC 把「预留—确认—取消」写进业务接口,控制力强但侵入业务。Saga 用一串本地事务加补偿动作换取可用性,代价是中间态对外可见。本地消息表和事务消息把一致性问题转化为可重试的投递问题。无论选哪种,都必须回答:失败点在哪里、补偿边界到哪里、补偿本身是否幂等、什么情况下需要人工介入。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

6个视频带你全方位了解腾讯云TDSQL分布式数据库:零基础了解tdsql、核心技术架构原理解析、安装部署、分布式事务实现机制、高可用技术解决方案、实例创建与使用

云贝教育 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能说明两阶段提交的阻塞来源,并判断哪些场景不适合使用它
  • 能用「预留—确认—取消」描述 TCC 的三个阶段,并指出它对业务接口的侵入
  • 能为一个跨服务流程设计 Saga 的补偿序列,并说明中间态对外的可见性
  • 能论证补偿动作必须幂等的原因,并给出实现幂等的具体手段

核心讲解

从阻塞到补偿

两阶段提交把提交拆成投票与提交两步:协调者先询问所有参与者能否提交,全部同意后再通知提交。它的问题在于,参与者在投票之后、收到最终决定之前必须保持资源锁定;如果协调者此时故障,参与者既不能提交也不能回滚,只能等待。三阶段提交通过增加一个预提交阶段缩短阻塞窗口,但在网络分区下会引入新的不一致可能。跨服务、跨组织、耗时较长的业务流程,通常不适合直接使用这类阻塞式协议。

补偿型方案换了一个思路:不追求全局原子,而是让每一步都是可以单独提交的本地事务,一旦后续步骤失败,就按相反顺序执行补偿动作把已完成的步骤撤销。Microsoft 的架构模式文档把这一模式称为 Saga,并把撤销动作单独描述为补偿事务模式。它的代价是中间态会被外部观察到——用户可能先看到「已下单」,随后看到「已取消」,界面文案和通知策略必须为此设计。

补偿的边界与幂等

补偿不等于回滚。回滚是把数据恢复到事务开始前的状态,而补偿是执行一个业务上抵消原动作的新操作:已发出的短信无法撤回,只能再发一条更正通知;已扣的款项通过退款抵消,账目上会留下两条记录。因此设计补偿时必须逐个动作判断:这一步是否可补偿?补偿是否会产生新的外部影响?有没有一个时间点之后就只能人工处理?把这些写成表格,比笼统地说「失败会回滚」诚实得多。

补偿动作会被重试,所以它必须幂等:同一个补偿被执行两次,结果应与执行一次相同。常见实现是为每次业务操作分配全局唯一的事务号,补偿时以该事务号作为幂等键,先检查是否已补偿再执行。此外还要考虑「空补偿」——补偿请求先于正向请求到达时,系统必须记录这一事实并拒绝随后到达的正向请求,否则会出现悬挂,这是 TCC 类实现中最容易遗漏的边界。

实践任务

为一个跨订单、库存、支付三个服务的下单流程,分别用 Saga 和本地消息表画出正常路径与补偿路径,并逐个失败点写出处置动作。

  • 画出下单流程的正常路径:订单创建、库存预留、支付扣款、订单确认,标出每一步的本地事务边界。
  • 为每一步写出对应的补偿动作,并逐个判断该补偿是否会产生新的外部影响(如通知、账目记录)。
  • 标出至少四个失败点:库存不足、支付超时未知结果、补偿失败、补偿请求先于正向请求到达;为每个失败点写出处置动作与人工介入条件。
  • 为补偿设计幂等键与状态机,说明如何防止空补偿与悬挂,并把方案与本地消息表方案在实现成本、可观测性、恢复难度上做对比。

自测与答案

第 1 题

为什么说 Saga 的补偿不能简单理解为「回滚」?请举一个补偿会留下痕迹的例子。

尚未检查本题。

查看答案与评价要点

参考答案:Saga 的每一步都是已提交的本地事务,无法撤销,只能执行业务上抵消它的新操作。例如已成功扣款只能通过退款抵消,账目上会同时存在扣款与退款两条记录;已发送的通知无法收回,只能补发更正通知。因此补偿会留下可被外部观察到的痕迹。

评价要点:指出每步已提交、无法回滚;说明补偿是新的抵消操作;给出退款、通知等会留痕的具体例子

第 2 题

什么是空补偿与悬挂?为什么它们会导致资源无法释放?

尚未检查本题。

查看答案与评价要点

参考答案:空补偿指补偿请求先于正向请求到达(例如正向请求超时后被判定失败并触发补偿,但它随后才真正到达);若系统直接忽略这次补偿,随后到达的正向请求仍会预留资源,且不会再有补偿到来,这个预留就悬挂在那里无法释放。正确做法是记录已补偿的事务号,并让随后到达的正向请求检查该记录后直接拒绝。

评价要点:准确描述补偿早于正向请求的时序;说明悬挂导致资源长期占用;给出记录事务号并拒绝迟到正向请求的处理

尚未完成自测。

今日完成标准

  • 提交 Saga 与本地消息表两种方案的流程图,正常路径与补偿路径都完整
  • 至少四个失败点各有明确处置动作、重试策略与人工介入条件
  • 补偿幂等方案写明幂等键、状态机与空补偿处理,并对两种方案做出有依据的取舍结论

常见错误与纠正提示

  • 把补偿说成回滚,忽略中间态已被用户和外部系统看到
  • 只设计正向流程的重试,不设计补偿失败后的处置,导致故障时无人负责
  • 补偿动作不做幂等,重试后产生重复退款或重复释放库存

分层任务

基础任务

在教师给出的流程骨架上补齐每一步的补偿动作,并说明哪一步之后只能人工处理。

标准任务

独立完成 Saga 与本地消息表两种方案的设计与对比,覆盖四个失败点。

挑战任务

为该流程补充一份可执行的演练脚本设计:如何注入支付结果未知、如何验证补偿幂等、如何判定演练通过。

关联知识点

延伸阅读

学习状态:未学习

Day 27

网关与服务网格

建议时长:75 分钟

本日 CO:CO1 CO2 CO8

本日概要

网关处理南北向流量:路由、认证、限流、熔断和协议转换集中在系统入口,一个组件即可对外收敛策略。服务网格用边车代理接管东西向流量,把重试、超时、流量切分和 mTLS 从业务代码下沉到基础设施,Istio 用 VirtualService 与 DestinationRule 这类配置对象描述这些规则。两者职责有重叠但不等价,叠加使用会增加一跳延迟与排障复杂度。灰度发布的关键是分流依据——按权重还是按请求头,二者的可复现性与可回滚性完全不同;故障隔离则依赖舱壁、超时预算和可观测指标。

听书与视频

本日听书

7 分钟 · MP3 · 双主持人讲解

B 站讲解

快速理解 Service Mesh

程序猿DD · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能区分南北向与东西向流量,并说明网关与服务网格各自的职责边界
  • 能用 Istio 的流量管理概念描述一次按权重或按请求头的灰度分流
  • 能解释 mTLS 在服务网格中解决了什么问题,以及它不解决什么问题
  • 能为一个服务设计超时、重试与舱壁参数,并说明这些参数之间必须相容的原因

核心讲解

入口与内部:两类流量,两套治理

网关位于系统入口,承担 TLS 终止、认证鉴权、路由、限流、熔断和协议转换。把这些策略集中在入口的好处是对外契约唯一、变更点集中;代价是网关本身成为关键路径,其容量、配置发布方式和故障域都需要单独设计。nginx 的负载均衡文档给出了轮询、最少连接、哈希等基础策略,以及健康检查与后端权重的配置方式,这些是理解更复杂网关产品的基础。

服务网格关注服务之间的调用。边车代理与业务容器同 Pod 部署,接管进出流量,从而可以在不改业务代码的前提下实施重试、超时、熔断、流量镜像和细粒度分流。Istio 的流量管理概念文档把路由规则与目标策略分成 VirtualService 与 DestinationRule 两类对象。需要清醒的是:网格增加了一跳代理,带来额外延迟与资源开销,也让排障链路变长——引入之前应先确认现有问题确实需要它。

灰度、mTLS 与故障隔离

灰度发布的分流依据决定了它的可解释性。按权重分流实现简单,但同一个用户在多次请求中可能落到不同版本,不适合有状态或多步流程的场景;按请求头或用户标识分流可以保证同一用户始终落到同一版本,便于复现问题和收集反馈,代价是需要在入口稳定地注入这些标识。无论哪种方式,都必须预先写出回滚触发条件——哪个指标、超过什么阈值、观察多长时间、由谁决定。

mTLS 让通信双方互相出示并校验证书,解决的是「这个调用方是谁」和「链路是否被窃听篡改」,Istio 的安全概念文档把身份、证书签发与策略执行放在一起描述。但 mTLS 不解决授权粒度问题:证明了身份之后,谁能访问哪个接口仍需要单独的授权策略。故障隔离同样要成套设计:舱壁限制单个下游能占用的并发与连接,超时预算保证上游超时大于下游超时之和,重试次数必须与超时预算相容,否则重试会在上游超时后仍在消耗下游容量。

实践任务

为一个已有服务设计灰度发布与故障隔离方案,写出分流规则、超时与重试预算、回滚触发条件和需要观察的指标。

  • 选定一个服务,画出请求从客户端经网关到服务、再到下游依赖的完整路径,标出 TLS 终止点、认证点和限流点。
  • 设计灰度规则:写出分流依据(权重或请求头)、初始比例、放量步骤与每一步的观察时长,并说明为何选择该依据。
  • 写出超时与重试预算表:每一跳的超时值、重试次数与退避策略,并验算上游超时是否大于下游超时与重试的总和。
  • 定义回滚触发条件与观察指标(如错误率、P99 延迟、饱和度),写明阈值、观察窗口与决策人;标注哪些阈值来自历史数据、哪些是初始假设。

自测与答案

第 1 题

按权重灰度与按请求头灰度分别适合什么场景?为什么多步业务流程通常不宜只用权重分流?

尚未检查本题。

查看答案与评价要点

参考答案:按权重适合无状态、单次请求即可完成的场景,实现简单;按请求头或用户标识适合需要同一用户稳定落到同一版本的场景,便于复现与收集反馈。多步流程若只用权重,同一用户的不同步骤可能落到不同版本,导致状态不一致且问题难以复现。

评价要点:说明权重分流的简单性与无状态适用性;说明按标识分流保证用户版本一致;指出多步流程跨版本会造成状态不一致或难复现

第 2 题

一个调用链上游超时 1 秒,下游超时 2 秒且重试 2 次。这个配置会产生什么问题?

尚未检查本题。

查看答案与评价要点

参考答案:上游在 1 秒后已经放弃并向用户返回失败,但下游仍在继续执行并重试,最长可能占用 6 秒的容量,这部分工作对用户已无价值,却持续消耗连接与线程,故障时会加速资源耗尽。正确做法是让上游超时大于下游超时与重试的总和,或让上游取消信号能向下游传递。

评价要点:指出上游已放弃而下游仍在执行;算出重试导致的无效占用时间;提出调整超时预算或传递取消信号

尚未完成自测。

今日完成标准

  • 提交包含 TLS 终止、认证、限流位置的请求路径图,并区分南北向与东西向治理点
  • 灰度方案写明分流依据、放量步骤、观察指标与回滚触发条件
  • 超时与重试预算表通过相容性验算,并说明各数值的来源是历史数据还是初始假设

常见错误与纠正提示

  • 同时叠加网关与服务网格却没有划分职责,导致同一策略在两处配置且互相覆盖
  • 认为启用 mTLS 就等于完成了安全治理,忽略接口级授权仍需单独配置
  • 灰度只定义放量比例,不定义回滚条件与观察指标,出问题时只能凭感觉决策

分层任务

基础任务

在教师提供的路径图上标出 TLS 终止、认证、限流位置,并说出每一处的作用。

标准任务

独立完成灰度方案与超时重试预算表,并通过相容性验算。

挑战任务

为该服务补充一份故障隔离设计:舱壁参数、降级开关、依赖不可用时的兜底响应,以及验证这些机制生效的方法。

关联知识点

延伸阅读

学习状态:未学习

Day 28

中间件复盘

建议时长:90 分钟

本日 CO:CO1 CO2 CO8

本日概要

本周收尾不引入新组件,而是把数据库、缓存、消息队列、分布式事务与流量治理整理成一棵可复核的选型决策树。合理的提问顺序是:数据形态与一致性要求是什么,吞吐与延迟目标是多少,团队的运维与安全边界在哪里,最后才是选哪个产品。每个分支都要写出触发条件、被放弃方案的原因和回退路径;价格、容量这类易变数字应标记为需要在实际选区重新核验的假设,而不是写死在报告里。这份决策树也是第 4 周作业与阶段项目的骨架。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

【第十章】go实战视频教程golang数据库消息队列操作mysql介绍以及使用事务sqlx的使用redis使用消息队列使用

地鼠文档 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能按「数据形态与一致性 → 吞吐与延迟 → 运维与安全边界 → 产品」的顺序组织选型提问
  • 能为每个决策分支写出触发条件、放弃其他方案的理由和回退路径
  • 能识别报告中哪些数字是易变假设,并给出重新核验的入口而不是直接写死
  • 能把本周的一致性、幂等、补偿和流量治理结论串成一个可复核的整体方案

核心讲解

先问约束,再问产品

常见的选型错误是从产品名开始比较。更稳妥的顺序是先确定约束:数据是结构化还是半结构化,读写比例如何,是否需要跨行跨表的事务,能接受多长的收敛窗口;然后是量级,峰值 QPS、数据总量、增长速度、延迟目标各是多少;再然后是团队能力与安全边界,谁来运维、是否有能力处理主从切换、数据能否出域。只有这些确定之后,产品比较才有意义,否则就是在比较无关的指标。

决策树的每个分支都应当可被复核。这意味着分支上要写清触发条件(满足什么条件时走这一支)、被放弃方案的具体原因(不是「不好」,而是「在本场景的哪个约束上不满足」)、以及回退路径(如果这条路走不通,退回到哪个节点、代价是什么)。这样写出来的报告,别人可以按同样的条件重走一遍并得到相同结论,这正是本课程反复强调的可复核性。

把易变数字与稳定结论分开

选型报告里最容易过期的是价格、实例规格、配额上限和性能基准。这类数字随地域、时间和合同条款变化,写死在报告里会让整份文档在几个月后失去可信度。更好的做法是记录计费单位与成本驱动因素(例如按存储量、按请求数、按出网流量计费),给出官方核验入口和本次访问日期,并用低中高三档用量情景做敏感性分析,而不是给一个精确到小数点的总价。

相对稳定的是机制性结论:二级索引需要回表、分区数决定消费并行度上限、补偿必须幂等、上游超时应大于下游超时与重试之和。这些结论来自系统机制而非某个版本的实现细节,可以放心写进决策树。把两类内容分开排版——机制结论作为判断依据,易变数字作为需要核验的输入——报告的生命周期会长得多。

实践任务

把本周五天的结论整合成一份中间件选型决策树,并用一个电商或内容平台的具体场景走通至少两条完整分支。

  • 把本周五天的核心结论各摘录两条,标注它属于机制性结论还是与版本/规格相关的易变事实。
  • 绘制决策树:第一层按数据形态与一致性要求分支,第二层按吞吐与延迟目标分支,第三层按运维与安全边界分支,叶子节点才是候选方案。
  • 选定一个电商或内容平台场景,沿决策树走通至少两条完整分支,逐节点写出触发条件、放弃理由和回退路径。
  • 列出报告中所有易变数字,为每一项给出官方核验入口、本次访问日期和低中高三档用量情景;未核验的一律标记为待验证假设。

自测与答案

第 1 题

为什么选型报告应当从约束开始,而不是从产品对比开始?

尚未检查本题。

查看答案与评价要点

参考答案:不同产品的优势只有在具体约束下才可比较:一致性要求、读写比例、数据量级、延迟目标和团队运维能力决定了哪些指标相关。先比较产品会导致用与场景无关的指标(如峰值基准)排名,结论无法复核,也无法解释为什么放弃其他方案。

评价要点:指出约束决定哪些指标相关;说明先比产品会用到无关指标;强调可复核性与放弃理由的可解释性

第 2 题

在选型报告中,应如何处理价格与性能基准这类易变数字?

尚未检查本题。

查看答案与评价要点

参考答案:不应写死具体数值,而应记录计费单位与成本驱动因素、官方核验入口和本次访问日期,并用低中高三档用量情景做敏感性分析;性能基准需附测试条件(负载、并发、数据量、版本),并标明是实测还是引用。所有未经本人核验的数字都标记为待验证假设。

评价要点:提出记录计费单位与成本驱动因素;要求附核验入口与访问日期;要求区分实测与引用并标注待验证

尚未完成自测。

今日完成标准

  • 提交三层结构的中间件选型决策树,叶子节点为候选方案而非产品排名
  • 至少两条完整分支写出触发条件、放弃理由和回退路径,并对应到一个具体业务场景
  • 易变数字清单完整,每项有核验入口与访问日期,未核验项被明确标记为待验证假设

常见错误与纠正提示

  • 决策树只有产品名而没有触发条件,别人无法按同样条件复核
  • 把某次基准测试结果当作产品的固有性能,忽略负载、并发与版本条件
  • 报告中混排稳定的机制结论与易变的价格规格,导致整份文档很快过期

分层任务

基础任务

在教师给出的决策树骨架上补齐叶子节点,并为其中一条分支写出触发条件。

标准任务

独立完成三层决策树并走通两条完整分支,附易变数字清单。

挑战任务

为决策树补充一份「反例检查」:给出两个看似合适却应被否决的方案,并说明是哪个约束把它们排除的。

关联知识点

延伸阅读

学习状态:未学习