首页 > 解决方案 > 为什么有一个监督树而不是一个集中的监督者?

问题描述

我正在学习 Elixir 和 Erlang/OTP,并想了解监督树在构建高可用性系统中的重要性。

我可以看到主管在管理工作进程生命周期中的重要性。但是,我还是想知道为什么有些应用程序需要以层次结构的形式组织主管,而不是只有一个主管来管理所有的工作人员?拥有我天真地忽略的这种结构有什么实际好处吗?

借用Programming Elixir书中的一个例子,在哪种情况下我们更喜欢第一种结构而不是第二种结构?

1.  MainSupervisor
    ├── StashWorker
    └── SubSupervisor
        └──SequenceWorker

2.  MainSupervisor
    ├── StashWorker
    └── SequenceWorker

标签: erlangelixirerlang-supervisor

解决方案


你可能忽略的是著名的“让它崩溃”哲学,它使进程崩溃并重新启动 OTP 中的一等公民。我们不会将进程崩溃视为失败,而是将其视为正确重做它而无需手动处理错误的机会。

主要原因是允许对失败时应该重新启动的内容进行更细粒度的控制。为此,我们有strategies. 或者,正如@Andree 在评论中重申的那样:

通过在层次结构中组织监督,我们可以更细粒度地控制系统在系统子集发生故障时应如何响应

想象一下应用程序有一个负责远程连接的进程和一堆进程,它们都使用这个资源。当连接进程崩溃时,无论如何,它都会被其主管重新启动,但它pid会发生变化。这意味着所有依赖于此的进程也pid应该重新启动。有了:rest_for_one策略,就很容易开箱即用。

此特定示例的另一种方法是管理进程中的连接,在树的另一部分进行监督,并在连接问题时手动使池的监督者使用此连接重新初始化所有池。

更重要的是,我们可能希望手动使处理此连接的进程崩溃以重新初始化它,而不是编写防御性代码,就像if no_conn, do: reload_config_and_restart_connection我们让它崩溃并由监督树使用新的正确配置重新初始化一样。

最后但并非最不重要的一点是,如果主管不捕获出口,它也会崩溃,并向上传播。这样我们就可以重新初始化监督树的整个分支,而无需编写任何代码。


推荐阅读