【问题标题】:Restarting erlang process and preserving state重新启动erlang进程并保留状态
【发布时间】:2012-10-23 08:46:41
【问题描述】:

我有一个启动多个子进程的主管进程。目前,当孩子去世时,我会使用新的 Pid 生成一个新进程。这意味着我丢失了刚刚死亡的子进程的状态信息。我希望我的客户始终使用相同的标识符与子进程进行通信。尽管子进程可能会死亡并被主管重新启动。

我正在考虑使用唯一名称注册子进程并将子状态存储在 ets 表中。问题是 - 在 Erlang 中解决此类问题的推荐方法是什么?

谢谢!

【问题讨论】:

    标签: erlang


    【解决方案1】:

    在 ets 表中存储进程状态有助于在崩溃之间保持状态,我通常使用全局注册表来为进程提供持久名称。 (玩家 200 将注册为 {player, 200}。)我不建议使用本地注册表,因为它要求您使用原子,如果您有很多子进程,您可以通过动态创建它们(如 player_200、player_201 等)

    不过,在 ets 表中存储子状态有其自身的风险和问题。如果一个孩子在发生错误和保存到 ets 表之间崩溃,你应该没问题。但是,如果您处理的数据导致孩子保存垃圾状态,然后在处理下一条消息时崩溃怎么办?您将重新启动该过程,从 ets 表中加载错误状态,然后再次崩溃您的下一条消息。当然有办法解决这个问题,但你应该意识到这是一种可能性并解决它。

    虽然 Erlang 隐藏了将 ets 表分配给所有进程的问题,但这样做的代价是 CPU 和潜在的争用。如果您要对 ets 表进行大量更改,则需要为性能付出代价。

    如果您的孩子崩溃了,您不应该为他们寻找一种方法来消除错误条件吗?我通常会将进程崩溃视为我需要解决根本原因和修复的问题。 ?

    【讨论】:

    • 我对使用 ets 表存储子进程状态的最大担忧是我可能引入的潜在瓶颈。有许多进程经常更改状态,您需要它们在每次更改发生时用新状态更新拥有 ets 表的进程。每当子进程死亡时,我需要以崩溃前的相同状态重新启动当子进程死亡时,它会通过发送 {'EXIT', Pid, Reason} 通知主管。如果子进程也可以发送崩溃前的状态,我可以以相同的状态重新启动,并且不需要将更新发送到 ets 表。
    • 我认为这在 Erlang 中是不可能的,但总的来说我想这将是一个不错的功能。类似于在孩子崩溃时将进程堆栈发送给主管
    • @Mark 我在回答中引用的文章解释了当拥有进程崩溃时如何使用 ETS 表赠送/继承到另一个进程,听起来像你想要的那样?
    【解决方案2】:

    使用 ETS 表可能是保持状态的方法。 Vinoski's article 讨论了如何在保留 ETS 表数据的同时重新启动崩溃的进程。

    正如@user30997 指出的那样,表中的数据实际上可能是进程崩溃的原因,因此在重新启动时,您可能想要验证表(或设置进程重新启动次数的限制......)

    对于将进程与 id 相关联,您应该查看 gproc,这非常适合。

    【讨论】:

      【解决方案3】:

      使用事件源,持久化所有事件,并重放以重建状态。如果您需要快速回放,请制作快照。下面的例子: https://github.com/bryanhunter/cqrs-with-erlang/tree/ndc-oslo

      其实基于这个例子构建一个完整的框架就好了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-19
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 2012-05-24
        • 2011-10-24
        相关资源
        最近更新 更多