gpt4 book ai didi

architecture - 你如何设计一个基于 Erlang/OTP 的分布式容错多核系统的架构?

转载 作者:行者123 更新时间:2023-12-03 00:26:45 25 4
gpt4 key购买 nike

我想构建一个基于 Erlang/OTP 的系统来解决“令人尴尬的并行”问题。

我已经阅读/浏览了:

  • 向你学习一些 Erlang;
  • 编程 Erlang(阿姆斯壮);
  • Erlang 编程(Cesarini);
  • Erlang/OTP 在行动。

  • 我已经掌握了流程、消息传递、主管、gen_servers、日志记录等的要点。

    我确实理解某些架构选择取决于所关注的应用程序,但我仍然想知道 ERlang/OTP 系统设计的一些一般原则。

    我应该从几个带有主管的 gen_servers 开始,然后逐步构建吗?

    我应该有多少个主管?我如何决定系统的哪些部分应该基于流程?我应该如何避免瓶颈?

    我应该稍后添加日志记录吗?

    Erlang/OTP 分布式容错多处理器系统架构的一般方法是什么?

    最佳答案

    我应该从几个带有主管的 gen_servers 开始,然后逐步构建吗?

    你在这里错过了 Erlang 架构中的一个关键组件:应用程序! (即OTP应用的概念,不是软件应用)。

    将应用程序视为组件。系统中的一个组件解决一个特定的问题,负责一组连贯的资源或从系统中抽象出一些重要或复杂的东西。

    设计 Erlang 系统的第一步是决定需要哪些应用程序。有些可以按原样从网上提取,我们可以将这些称为库。其他你需要自己编写(否则你就不需要这个特定的系统)。我们通常将这些应用程序称为业务逻辑(通常您还需要自己编写一些库,但保持库与将所有内容联系在一起的核心业务应用程序之间的区别很有用)。

    我应该有多少个主管?

    对于要监控的每种流程,您都应该有一名主管。

    一堆一模一样的临时工?一位主管来统治他们。

    不同的流程有不同的职责和重启策略?每个不同类型进程的主管,在正确的层次结构中(取决于什么时候应该重新启动以及哪些其他进程需要与它们一起关闭?)。

    有时将一堆不同的流程类型放在同一个主管下是可以的。当您有几个始终运行的单例进程(例如,一个 HTTP 服务器主管、一个 ETS 表所有者进程、一个统计信息收集器)时,通常就是这种情况。在这种情况下,为每个主管配备一名主管可能过于繁琐,因此通常会添加一位主管。在执行此操作时请注意使用特定重启策略的含义,因此您不要取消统计过程,例如,万一您的 Web 服务器崩溃(one_for_one 是在这种情况下最常用的策略) )。注意不要在 one_for_one 中的进程之间有任何依赖关系。导师。如果一个进程依赖于另一个崩溃的进程,它也会崩溃,触发监督者的重启强度过于频繁,监督者本身也会过早崩溃。这可以通过使用两个不同的主管来避免,这将通过配置的强度和周期( longer explanation )完全控制重新启动。

    我如何决定系统的哪些部分应该基于流程?

    系统中的每个并发事件都应该在它自己的进程中。错误的并发抽象是 Erlang 系统设计者一开始最常犯的错误。

    有些人不习惯处理并发;他们的系统往往有太少。一个进程,或几个巨大的进程,按顺序运行所有内容。这些系统通常充满了代码异味,并且代码非常死板且难以重构。这也使它们变慢,因为它们可能不会使用 Erlang 可用的所有内核。

    其他人立即掌握并发概念,但未能最佳地应用它们;他们的系统倾向于过度使用流程概念,使许多流程保持空闲等待其他正在工作的流程。这些系统往往过于复杂且难以调试。

    本质上,在这两种变体中,您会遇到相同的问题,您没有使用所有可用的并发性,也没有从系统中获得最大性能。

    如果你坚持 single responsibility principle并遵守规则,为系统中的每个真正并发的事件制定一个流程,您应该没问题。

    有空闲进程是有正当理由的。有时他们保持重要状态,有时你想暂时保留一些数据然后丢弃进程,有时他们等待外部事件。更大的陷阱是通过一长串大部分不事件的进程传递重要消息,因为它会因大量复制而降低系统速度并使用更多内存。

    我应该如何避免瓶颈?

    很难说,很大程度上取决于你的系统和它在做什么。但是,通常情况下,如果您在应用程序之间有良好的职责分工,您应该能够将似乎是瓶颈的应用程序与系统的其余部分分开扩展。

    这里的黄金法则是测量,测量,再测量!在您进行测量之前,不要认为您有什么需要改进的地方。

    Erlang 的伟大之处在于它允许您将并发隐藏在接口(interface)后面(称为隐式并发)。比如你使用一个功能模块API,一个普通的module:function(Arguments)接口(interface),这反过来可以产生数千个进程,而调用者不必知道。如果您的抽象和 API 正确,您可以在开始使用库后对其进行并行化或优化。

    话虽如此,这里有一些一般指导方针:

  • 尝试直接向接收者发送消息,避免通过中间进程引导或路由消息。否则系统只会花时间移动消息(数据)而没有真正工作。
  • 不要过度使用 OTP 设计模式,例如 gen_servers。在很多情况下,你只需要启动一个进程,运行一段代码,然后退出。为此, gen_server 是矫枉过正的。

  • 还有一个额外的建议:不要重复使用流程。在 Erlang 中生成一个进程既便宜又快速,以至于一旦进程生命周期结束就重新使用它是没有意义的。在某些情况下,重用状态(例如文件的复杂解析)可能是有意义的,但最好规范地存储在其他地方(在 ETS 表、数据库等中)。

    我应该稍后添加日志记录吗?

    您现在应该添加日志记录!有一个很棒的内置 API,名为 Logger来自版本 21 的 Erlang/OTP 附带:
    logger:error("The file does not exist: ~ts",[Filename]),
    logger:notice("Something strange happened!"),
    logger:debug(#{got => connection_request, id => Id, state => State},
    #{report_cb => fun(R) -> {"~p",[R]} end}),

    这个新 API 有几个高级功能,应该涵盖您需要日志记录的大多数情况。还有较旧但仍被广泛使用的 3rd 方库 Lager .

    Erlang/OTP 分布式容错多处理器系统架构的一般方法是什么?

    总结一下上面所说的:
  • 将您的系统划分为多个应用程序
  • 根据流程的需求和依赖性,将流程置于正确的监督层次结构中
  • 为系统中的每个真正并发的事件制定一个流程
  • 维护面向系统中其他组件的功能 API。这让您:
  • 重构您的代码而不更改使用它的代码
  • 事后优化代码
  • 在需要时分发您的系统(只需调用 API 后面的另一个节点!调用者不会注意到!)
  • 更轻松地测试代码(设置测试工具的工作更少,更容易理解如何使用它)
  • 开始使用 OTP 中提供给您的库,直到您需要一些不同的东西(您会知道,到时候)

  • 常见的陷阱:
  • 进程过多
  • 进程太少
  • 路由过多(转发的消息、链接的进程)
  • 应用程序太少(实际上我从未见过相反的情况)
  • 没有足够的抽象(很难重构和推理。也很难测试!)
  • 关于architecture - 你如何设计一个基于 Erlang/OTP 的分布式容错多核系统的架构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7307634/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com