分布式应用 | 9. Distributed Applications
9分布式应用
9.1 简介
在具有多个Erlang节点的分布式系统中,可能需要以分布式方式控制应用程序。如果运行某个应用程序的节点出现故障,则该应用程序将在另一个节点上重新启动。
这样的应用程序被称为分布式应用程序
。请注意,它是分发的应用程序的控制。例如,所有应用程序都可以在其他节点上使用服务。
由于分布式应用程序可以在节点之间移动,所以需要一些寻址机制来确保它可以被其他应用程序解决,而不管它当前正在执行哪个节点。这个问题在这里没有解决,但是Kernel中的global
or pg2
模块可以用于这个目的。
9.2指定分布式应用程序
分布式应用程序由应用程序控制器和分布式应用程序控制器进程控制dist_ac
。这两个进程都是内核应用程序的一部分。通过使用以下配置参数(另请参阅kernel(6)
)配置内核应用程序来指定分布式应用程序:
distributed = [{Application, [Timeout,] NodeDesc}]
- 指定应用程序
Application = atom()
可以执行的位置。
NodeDesc = [Node | {Node,...,Node}]
是按优先级顺序排列的节点名称列表。元组中节点之间的顺序未定义。
Timeout = integer()
指定在另一个节点上重新启动应用程序之前要等待多少毫秒。它默认为0。
为了使应用程序控制能够正常工作,分布式应用程序可以运行的节点必须相互联系并协商启动应用程序的位置。这是在内核中使用以下配置参数完成的:
sync_nodes_mandatory = [Node]
- 指定必须启动哪些其他节点(在指定的超时范围内sync_nodes_timeout
)。
sync_nodes_optional = [Node]
- 指定可以启动哪些其他节点(在指定的超时范围内sync_nodes_timeout
)。
sync_nodes_timeout = integer() | infinity
- 指定等待其他节点启动的毫秒数。
启动时,节点等待由指定的所有节点sync_nodes_mandatory
,并sync_nodes_optional
就上来了。当所有节点都启动时,或者当所有强制节点都启动并且由时间指定的时间sync_nodes_timeout
已过时,所有应用程序都会启动。如果不是所有强制节点都启动,则节点终止。
例子:
应用程序myapp
将在节点上运行cp1@cave
。如果此节点关闭,myapp
则在cp2@cave
或重新启动cp3@cave
。系统配置文件cp1.config
的cp1@cave
可以看看如下:
[{kernel,
[{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]},
{sync_nodes_mandatory, [cp2@cave, cp3@cave]},
{sync_nodes_timeout, 5000}
]
}
].
对于系统配置文件cp2@cave
和cp3@cave
是相同的,除了强制节点的列表,这是要[cp1@cave, cp3@cave]
对cp2@cave
和[cp1@cave, cp2@cave]
对cp3@cave
。
注意
所有涉及的节点必须有相同的价值distributed
和sync_nodes_timeout
。否则,系统行为未定义。
9.3 启动和停止分布式应用程序
当所有涉及的(强制性)节点都已启动时,可以通过application:start(Application)
在所有这些节点
上调用来启动分布式应用程序。
Releases
可以使用引导脚本(请参阅)自动启动应用程序。
应用程序在distributed
配置参数中的节点列表中列出的第一个操作节点处启动。应用程序像往常一样启动。也就是说,创建应用程序主文件并调用应用程序回调函数:
Module:start(normal, StartArgs)
例子:
继续上一节中的示例,启动三个节点,指定系统配置文件:
> erl -sname cp1 -config cp1
> erl -sname cp2 -config cp2
> erl -sname cp3 -config cp3
当所有节点都myapp
可以运行时,可以启动。这是通过调用application:start(myapp)
所有三个节点来实现的。然后开始cp1
,如下图所示:
图9.1:应用程序myapp - 情况1
类似地,必须通过调用application:stop(Application)
所有涉及的节点。
9.4故障转移
如果应用程序运行的节点出现故障,则在distributed
配置参数中的节点列表中列出的第一个运行节点处重新启动应用程序(在指定的超时之后)。这称为故障转移
。
应用程序以新节点的正常方式启动,即由应用程序主服务器调用:
Module:start(normal, StartArgs)
如果应用程序start_phases
定义了密钥(请参阅Included Applications
),则是一个例外。然后,该应用程序通过调用来启动:
Module:start{failover, Node}, StartArgs)
这里Node
是终止的节点。
例子:
如果cp1
发生故障,系统将检查其中哪一个节点cp2
或cp3
最少运行的应用程序数量,但要等待5秒钟cp1
才能重新启动。如果cp1
不重新启动并cp2
运行更少的应用程序cp3
,myapp
则重新启动cp2
。
图9.2:应用程序myapp - 情况2
假设现在cp2
也下降并且在5秒内不重新启动。myapp
现在重新启动cp3
。
图9.3:应用程序myapp - 情况3
9.5 接管
如果启动了一个节点,该节点根据distributed
分布式应用程序运行的节点具有更高的优先级,则应用程序将在新节点处重新启动并停在旧节点处。这被称为接管
。
应用程序由应用程序主调用启动:
Module:start{takeover, Node}, StartArgs)
此处Node
是旧节点。
实例:
如果myapp
正在运行cp3
,并且如果cp2
现在重新启动,则它不会重新启动myapp
,因为cp2
和cp3
节点之间的顺序未定义。
图9.4:应用程序myapp-情景4
但是,如果cp1
还重新启动,则该功能application:takeover/2
将myapp
移至cp1
,因为此cp1
优先级高于cp3
此应用程序。在这种情况下,Module:start{takeover, cp3@cave}, StartArgs)在
执行时cp1
启动应用程序。
图9.5:应用程序myapp-情景5