模块 07查看课程目录
00起跑线:两门语言,一台机器01先建立 BEAM 心智模型02Elixir 基础:让数据流过函数03Erlang 基础:读懂 BEAM 的母语04两种语法,一套语义05从裸进程理解并发06从手写循环推导 OTP07监督树与应用08状态、吞吐与背压09分布式与可运维性10Erlang ↔ Elixir 互操作11综合项目:可靠任务调度器
07
OTP中级ElixirErlangOTP

监督树与应用

可靠性来自清楚的故障域,不是“进程会自动重启”。

4检查点
6 小时预计完成
为什么先学这个

先修正心智模型,再增加 API

“Let it crash” 经常被误解为不处理错误。真正的含义是:在合适边界把不可恢复的局部状态交给监督者,由预先定义的策略恢复;可预期的业务错误仍应正常返回。

学完你能做到

可验证的学习目标

  • 能按故障依赖划分监督树
  • 能解释 one_for_one、one_for_all、rest_for_one
  • 能选择 permanent、transient、temporary restart
前置知识
  • 会实现 GenServer/gen_server
  • 理解 link 与 exit
最小心智模型

先抓住三个词

01

故障域

一组需要共同恢复或彼此隔离的组件。监督树结构应表达这种恢复关系。

02

restart intensity

在时间窗口内允许的最大重启次数。超过阈值,监督者自身退出,把问题上推。

03

Application

OTP 中可启动、可配置、可依赖的组件单元;根监督树通常从 application callback 启动。

双语代码桥

先对齐协议,再看标点

子进程顺序在 rest_for_one 下有恢复含义:前面的基础设施崩溃,会重启其后的依赖者。

Elixir
children = [
  {Registry, keys: :unique, name: Jobs.Registry},
  {DynamicSupervisor,
   strategy: :one_for_one,
   name: Jobs.Workers},
  Jobs.Dispatcher
]

Supervisor.start_link(
  children,
  strategy: :rest_for_one,
  name: Jobs.Supervisor
)
Erlang
init([]) ->
  Registry = #{
    id => jobs_registry,
    start => {jobs_registry, start_link, []}
  },
  Workers = #{
    id => jobs_workers_sup,
    start => {jobs_workers_sup, start_link, []},
    type => supervisor
  },
  Dispatcher = #{
    id => jobs_dispatcher,
    start => {jobs_dispatcher, start_link, []}
  },
  {ok, {{rest_for_one, 3, 5},
        [Registry, Workers, Dispatcher]}}.
LAB
可运行实验

杀掉不同位置,观察不同恢复半径

约 15–25 分钟

记录三个子进程 PID,分别终止 dispatcher 与 registry。比较哪些 PID 改变。

  1. 01

    启动监督树并记录所有 child PID

  2. 02

    让最后一个 child 异常退出

  3. 03

    让第一个 child 异常退出,再次记录 PID

在终端 / shell 中运行
Supervisor.which_children(Jobs.Supervisor)
预期观察
  • 最后 child 崩溃时只重启自己
  • 第一个 child 崩溃时,其后的依赖 child 都重启
故意弄坏

把 strategy 改为 one_for_all。再杀最后一个无关 child,观察过大的恢复半径。

这个实验能证明

restart strategy 与 child 顺序共同定义恢复范围。

这个实验不能证明

PID 重建不代表业务状态已经正确恢复;外部副作用、持久化和幂等仍需单独设计。

快速自测

什么时候 rest_for_one 最合适?

本章挑战

监督树答辩

为任务队列画出监督树,逐个说明每个 child 为什么是 permanent/transient/temporary,以及它与兄弟节点是否需要共同恢复。

提示 1轻推一下

从“谁拥有长期状态”开始。

提示 2缩小问题

动态任务与基础设施通常不使用同一 child spec。

提示 3接近实现

加入超过 restart intensity 时的系统行为。

提示 4用验收标准反推

从下面每一条验收标准倒推一个最小测试。若某条无法写成测试,先把表述改成可观察结果。

完成标准
  • 每条父子关系都有故障理由
  • 重启类型与正常退出语义匹配
  • 明确指出一个不应自动重试的业务错误
带走这三句话

复习卡

  1. 1监督树首先是故障依赖图。
  2. 2Let it crash 不等于忽略可预期错误。
  3. 3进程重启只是恢复动作的一部分,状态与副作用仍需设计。
继续核对

本章一手资料

OTP Design PrinciplesElixir Supervisor