复杂监管树
设计并实现复杂的嵌套监管层级,以有效管理依赖关系和故障域。
复杂监管树 是 CoddyKit 上的免费 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Supervision Trees: The Basics
In Erlang, supervisors are special processes that oversee other processes, called children. If a child process crashes, the supervisor can restart it, ensuring fault tolerance.
A supervision tree is formed when a supervisor itself becomes a child of another supervisor. This creates a hierarchy, much like an organizational chart.
Why Complex Trees?
As applications grow, a single supervisor isn't enough. Complex supervision trees allow us to:
- Manage dependencies: Group related processes so they start and stop together.
- Isolate failures: A crash in one part of the tree won't necessarily bring down unrelated parts.
- Improve modularity: Each supervisor can be responsible for a specific subsystem, making the application easier to understand and maintain.
Child Spec: Worker vs. Supervisor
Every process a supervisor manages is defined by a child specification. A child spec tells the supervisor how to start, restart, and shut down the child process.
Crucially, a child can be of two types:
worker: A regular process (like agen_server) that performs application logic.supervisor: Another supervisor process, forming a nested level in the tree.
The Worker: my_worker_module
Let's start with a simple worker process. This gen_server will be the leaf node in our supervision tree. It just prints messages when it starts or receives calls.
-module(my_worker_module).
-behaviour(gen_server).
-export([start_link/1, init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link(Id) ->
gen_server:start_link(?MODULE, Id, []).
init(Id) ->
io:format("Worker ~p starting...~n", [Id]),
{ok, Id}.
handle_call(Req, _From, State) ->
io:format("Worker ~p received call: ~p~n", [State, Req]),
{reply, ok, State}.
handle_cast(Msg, State) ->
io:format("Worker ~p received cast: ~p~n", [State, Msg]),
{noreply, State}.
handle_info(Msg, State) ->
io:format("Worker ~p received info: ~p~n", [State, Msg]),
{noreply, State}.
terminate(_Reason, State) ->
io:format("Worker ~p terminating...~n", [State]).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.The Nested Supervisor: my_nested_sup
This supervisor will manage our my_worker_module processes. It defines two workers, 'WorkerA' and 'WorkerB', each with slightly different restart strategies.
Notice how its child_specs define type => worker.
-module(my_nested_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
SupFlags = #{
strategy => one_for_one,
intensity => 10,
period => 1
},
ChildSpecs = [
#{
id => worker_A,
start => {my_worker_module, start_link, ["WorkerA"]},
type => worker,
restart => permanent,
shutdown => 5000,
modules => [my_worker_module]
},
#{
id => worker_B,
start => {my_worker_module, start_link, ["WorkerB"]},
type => worker,
restart => transient,
shutdown => 2000,
modules => [my_worker_module]
}
],
{ok, {SupFlags, ChildSpecs}}.The Top-Level Supervisor: my_app_sup
This is the root of our complex tree. It supervises my_nested_sup. Notice that its child_spec for my_nested_sup has type => supervisor. This is how you build nested trees!
-module(my_app_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
SupFlags = #{
strategy => one_for_one,
intensity => 10,
period => 1
},
ChildSpecs = [
#{
id => my_nested_sup_child,
start => {my_nested_sup, start_link, []},
type => supervisor,
restart => permanent,
shutdown => infinity,
modules => [my_nested_sup]
}
],
{ok, {SupFlags, ChildSpecs}}.Running the Complex Tree
To see our tree in action, compile all three modules (my_worker_module.erl, my_nested_sup.erl, my_app_sup.erl) and then start the top-level supervisor. You'll see the workers start up!
You can use supervisor:which_children(PidOrName) to inspect the tree.
% In the Erlang shell:
c(my_worker_module).
c(my_nested_sup).
c(my_app_sup).
{ok, MySupPid} = my_app_sup:start_link().
% Check the children of the top-level supervisor:
supervisor:which_children(MySupPid).
% Find the nested supervisor's PID:
{_, NestedSupPid, _, _} = lists:keyfind(my_nested_sup_child, 1, supervisor:which_children(MySupPid)).
% Check the children of the nested supervisor:
supervisor:which_children(NestedSupPid).Visualizing the Hierarchy
Our complex supervision tree looks like this:
my_app_sup(top-level supervisor)- supervises
my_nested_sup(a child supervisor)- supervises
worker_A(a worker process) - supervises
worker_B(a worker process)
- supervises
- supervises
This structure ensures that if worker_A crashes, only my_nested_sup handles it. If my_nested_sup itself crashes, my_app_sup will restart it, bringing worker_A and worker_B back to life.
Benefits of Complex Trees
Complex supervision trees are a cornerstone of building robust Erlang applications. They provide:
- Fault Isolation: Failures are contained to specific branches.
- Logical Grouping: Components with related functions are supervised together.
- Clear Responsibilities: Each supervisor has a well-defined set of processes it's responsible for.
- Scalability: Easier to add or remove subsystems without disrupting the entire application.
Quick Check: Supervision Trees
Which of the following are key benefits of using complex (nested) supervision trees in Erlang?
Recap: Complex Supervision
Today, we explored complex supervision trees in Erlang. We learned that supervisors can manage other supervisors, creating nested hierarchies. This powerful pattern enables robust fault tolerance by isolating failures, managing dependencies, and improving the modularity of your applications. By defining child specs with type => supervisor, you can build intricate and resilient Erlang systems.
用 AI 导师学习 Erlang — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 12
- 课程
- 48
常见问题解答
「复杂监管树」课时是免费的吗?
是的 — 「复杂监管树」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课程的其余内容,请升级到 CoddyKit PRO。 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课程共包含 4 节课。
「复杂监管树」这节课中我会学到什么?
设计并实现复杂的嵌套监管层级,以有效管理依赖关系和故障域。 你通过在浏览器中直接运行的动手代码来练习 Erlang OTP: Distributed & Fault-Tolerant Systems Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「复杂监管树」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课中编写并运行代码吗?
能。每节 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。