![](/img/trans.png)
[英]Building a fault-tolerant soft real-time web application with Erlang/OTP
[英]How do you design the architecture of an Erlang/OTP-based distributed fault-tolerant multicore system?
我想构建一个基于Erlang / OTP的系统,它解决了一个“令人难以置信的并行”问题。
我已阅读/浏览过:
我有进程,消息,监督,gen_servers,Logging等的要点。
我确实理解某些架构选择取决于所关注的应用程序,但我仍然想知道ERlang / OTP系统设计的一些一般原则。
我应该从一个主管的几个gen_servers开始,并逐步建立?
我应该有多少名主管? 如何确定系统的哪些部分应基于流程? 我该如何避免瓶颈?
我以后应该添加日志吗?
Erlang / OTP分布式容错多处理器系统架构的一般方法是什么?
你在这里错过了Erlang架构中的一个关键组件:应用程序! (也就是说,OTP应用程序的概念,而不是软件应用程序)。
将应用程序视为组件。 系统中的一个组件解决了一个特定的问题,负责一组连贯的资源或从系统中抽象一些重要或复杂的东西。
设计Erlang系统的第一步是确定需要哪些应用程序。 有些可以按原样从网络中提取,我们可以将其称为库。 您需要自己编写的其他人(否则您不需要这个特定的系统)。 我们通常将这些应用程序称为业务逻辑(通常您也需要自己编写一些库,但保持库与将所有内容绑定在一起的核心业务应用程序之间的区别很有用)。
您应该为要监控的每种流程都配备一名主管。
一堆相同的临时工? 一位主管统治他们。
不同的流程有不同的职责和重启策略? 每个不同类型的流程的主管,处于正确的层次结构中(取决于什么时候应该重新启动以及其他流程需要与它们一起下去?)。
有时可以在同一个主管下放置一堆不同的流程类型。 当您有一些将始终运行的单个进程(例如,一个HTTP服务器管理程序,一个ETS表所有者进程,一个统计信息收集器)时,通常会出现这种情况。 在这种情况下,每个人都有一个主管可能太过残忍,所以通常会在一个主管下面添加一个主管。 请注意在执行此操作时使用特定重新启动策略的含义,因此您不会one_for_one
统计信息过程,例如,万一您的Web服务器崩溃( one_for_one
是在这种情况下使用的最常见策略)。 注意不要在one_for_one
主管中的进程之间存在任何依赖关系。 如果一个进程依赖于另一个崩溃的进程,它也会崩溃,过于频繁地触发主管的重启强度,并且过早地使主管本身崩溃。 这可以通过具有两个不同的监督器来避免,这些监督者将通过配置的强度和周期完全控制重启( 更长的解释 )。
系统中的每个并发活动都应该在它自己的进程中。 错误的并发抽象是Erlang系统设计人员最常犯的错误。
有些人不习惯处理并发问题; 他们的系统往往太少了。 一个过程,或几个巨大的过程,按顺序运行一切。 这些系统通常充满代码气味,代码非常严格,难以重构。 它也使它们变慢,因为它们可能不会使用Erlang可用的所有核心。
其他人立即掌握并发概念,但未能以最佳方式应用它们; 他们的系统倾向于过度使用流程概念,使许多流程闲置等待正在工作的其他人。 这些系统往往不必要地复杂且难以调试。
从本质上讲,在两种变体中都会遇到同样的问题,您不会使用所有可用的并发性,并且您无法获得系统的最大性能。
如果您坚持单一责任原则并遵守规则为您的系统中的每个真正并发活动创建流程,那么您应该没问题。
有正当理由有闲置进程。 有时他们会保持重要的状态,有时你想暂时保留一些数据,然后放弃这个过程,有时他们会等待外部事件。 更大的缺陷是通过长链非常不活跃的进程传递重要消息,因为它会通过大量复制减慢系统速度并使用更多内存。
很难说,很大程度上取决于你的系统以及它正在做什么。 但是,一般来说,如果您在应用程序之间有一个良好的责任分工,那么您应该能够将与该系统其他部分分开的应用程序扩展为瓶颈。
这里的黄金法则是衡量,衡量,衡量 ! 在你测量之前,不要认为你有什么需要改进的地方。
Erlang的优点在于它允许您隐藏接口后的并发(称为隐式并发)。 例如,您使用功能模块API,一个普通的module:function(Arguments)
接口,它可以反过来生成数千个进程,而调用者不必知道这一点。 如果您的抽象和API正确,您可以在开始使用它之后始终并行化或优化库。
话虽如此,这里有一些一般的指导方针:
还有一个好处是:不要重复使用流程。 在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有几个高级功能,应该涵盖大多数需要记录的情况。 还有较旧但仍广泛使用的第三方图书馆Lager 。
总结一下上面说的:
常见的陷阱:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.