1

主要出于教育目的,我正在尝试编写任务(任务是 open_port({spawn_executable, Command}))调度程序。

我最终得到了像这样的树

        supervisor
        |        |
scheduler        receiver
gen_event        gen_event
                     |
                supervisor
                     |
                dispatcher
                gen_server
                     |
                supervisor
                |    |   |
             task1  ... taskN

换句话说:

  1. 最高主管启动调度程序和接收器并确保它们处于活动状态
  2. 接收器启动中间主管
  3. 中级主管启动调度程序并确保它处于活动状态
  4. 调度员启动底层主管
  5. 底层主管根据请求启动任务,并确保在出现错误时重新启动它们

  6. 在任何时候调度程序都准备好接受一个带有时间戳的任务,它应该在

  7. 当时间戳满足时,它会通知一些 event_manager
  8. 然后接收者由同一个事件管理器通知,并通过中间主管将消息传递给调度程序
  9. dispatcher 有一些业务逻辑,这就是为什么它不是无状态的,例如某些任务不能同时执行
  10. 当满足所有条件时,调度程序将任务传递给底层主管,确保任务执行,直到获得正常退出或绕过某些阈值
  11. 底部主管返回一条消息,然后向上向上传递给某个事件管理器
  12. 调度程序最终收到此消息,从其队列中删除任务或重新入队或其他

问题是:

  1. 我的行为正确吗?
  2. 结构是不是太复杂了?(但是,将来该系统将变得分布式。)
  3. 有没有办法将receiver+middle supervisor和dispatcher+bottom supervisor组合成两个模块,而不是四个同时实现4个行为?
  4. 或者有没有办法将receiver+dispatcher+bottom supervisor组合在一个模块中,省去中间supervisor,同时实现gen_event+gen_server+supervisor行为?
  5. 我是否错误地将行为视为 OO 语言中的接口或多重继承?(这让我提出问题 3 和 4。)

提前致谢。

PS IMO,一方面结构过于复杂;另一方面,这样的结构让我可以将它的任何块分发(例如,多个调度器到一个接收器,一个调度器到多个接收器,许多调度器到多个接收器,每个接收器有多个调度器,甚至每个调度器有多个底层监督器- 每一层都有自己的监督策略)。复杂性和可扩展性之间的平衡点在哪里?

4

1 回答 1

1

我的建议是简化您的设计,更像是:

        supervisor
        |        |
 dispatcher      |
 +scheduler      |
                 |
            supervisor
            |    |   |
         task1  ... taskN

即使从分发的角度来看,让单独的调度程序将事件发送到启动任务等的调度程序也没有太多好处。

dispatcher-scheduler 可以在 timer 模块的帮助下非常简单地完成,并且可以是一个 gen_server。Timer 可以发送可以在 handle_info 回调中处理的消息,也可以调用 gen_server 的 api 函数。

您还可以使用超时功能在下一个间隔之后唤醒 gen_server,这会更简单,因为您不必担心在添加新“任务”时取消计时器。

然后调度程序/调度程序调用supervisor:start_child以添加工作任务。

分配可以很容易地添加:调度程序/调度程序可以在一个单独的节点上,而不是二级主管。任务启动功能可以进一步分配,并且可能使用模块进行负载平衡。

回答你的五个问题:

  1. 我怀疑您在不需要的地方使用了 gen_event,但是由于不需要模块本身,因此可以通过删除它们来轻松修复。gen_event 是如果您希望能够在一个事件源上注册多个处理程序,您可以 1:1 使用它。监督树通常由监督者构建,监督者是其他监督者的直接孩子。

  2. 是的,它太复杂了,看起来有点像你用 OO 语言做的,表达能力较差。并且只是为可能的分发做准备是没有必要的。用像 Erlang 这样的函数式语言进行重构比你想象的要容易得多。因此,如果您看到需要,请开始使用简单和拆分功能。

3+4。请参阅我完全不同的建议。

  1. 它不像 OO 那样。OTP 中的行为只是将流程机制隐藏在通用模块中的回调模块。

即使使用我建议的简单结构,也有很大的灵活性(由 Erlang 提供给您),因为如果您想拥有多个调度程序,您可以使用 rpc 调用主管。您可以使用来自动负载均衡分配任务。并且调度程序部分可以很容易地与调度程序分离(然后都在顶级主管下),您可以将更常见的状态与调度程序分离。

于 2011-03-24T11:04:16.130 回答