Network programming 分布式Erlang—网络拆分恢复,并在分布式应用程序中使用heart

Network programming 分布式Erlang—网络拆分恢复,并在分布式应用程序中使用heart,network-programming,erlang,otp,Network Programming,Erlang,Otp,我有一个标准情况,两个分布式Erlang节点,一个主节点,一个备用节点 当我停止主机时,备用启动-故障转移,当我启动主机时,备用停止-接管。只要心脏没有打开,并且没有网络分裂,一切正常 但是,当我在大约60秒后断开主机与网络的连接时,待机状态会给我一条错误消息**正在删除(timedout)连接**,并且会像主机节点停止一样启动。这对我来说很有意义,它不知道主节点是否处于活动状态,并且epmd无法连接到主节点,因此它被从nodes()列表中删除。让我们暂时假设这是期望的结果 问题是,当连接恢复时

我有一个标准情况,两个分布式Erlang节点,一个主节点,一个备用节点

当我停止主机时,备用启动-故障转移,当我启动主机时,备用停止-接管。只要心脏没有打开,并且没有网络分裂,一切正常

但是,当我在大约60秒后断开主机与网络的连接时,待机状态会给我一条错误消息**正在删除(timedout)连接**,并且会像主机节点停止一样启动。这对我来说很有意义,它不知道主节点是否处于活动状态,并且epmd无法连接到主节点,因此它被从nodes()列表中删除。让我们暂时假设这是期望的结果

问题是,当连接恢复时,主设备和备用设备同时运行,而备用设备却忽略了主设备正在运行的事实。在masters初始化期间ping待机并不能解决此问题。我在待机状态下检查了nodes(),执行此操作后,它会看到主节点,但仍会继续运行

目前我的解决方案是创建一个进程,该进程监视层次结构中每个节点上方的所有节点,如果其中任何节点处于联机状态,则可以ping,该进程调用erlang:halt()来终止备用节点。它适用于简单的情况,但也许有人能告诉我是否有更好的方法?我在Elixir论坛上发现了一个类似的问题,所以它可能是一个已知的erlang问题,没有简单的解决方案

如果在网络拆分期间,您不希望两个节点并行运行,我猜需要使用外部监控应用程序

第二个主要问题是心脏。如果心脏按原样打开,故障转移就永远不会发生。如果heart在调用start之前处于休眠状态,则在调用应用程序start时会停止故障转移节点。因此,即使它无法启动主机,也要确保它无法访问重要资源,例如,它会停止故障转移节点,并且在无法启动主机后不会将其恢复。我不知道heart是否不应该与分布式应用程序一起使用,或者是否可以在尝试启动节点和停止故障转移节点之前运行一些erlang代码来检查资源是否可用

关于心脏的文档不是很好。很难找到HEART_命令的任何示例。我在应用程序中找到了一种将HEART_命令设置为脚本的方法,但是参数的长度是有限制的,而且据我所知,它没有文档中所述的那么长。例如,在再次调用应用程序启动之前,将睡眠计时器设置为60秒。它不能解决任何问题,因为在60秒内,如果主节点无法启动,它将停止故障转移节点并挂起。
heart:set_cmd(“sleep 60;/bin/myapp start”)

我现在的解决方案是让主版本的核心启动另一个版本,一个预加载程序,它对所有资源是否可用进行初步检查,如果可用,它将启动主版本应用程序,如果不可用,它将永远继续检查。这样,主应用程序在故障转移节点上运行时不会中断。因此,主版本已打开heart,而预加载程序未打开。我最终使用了一个bash脚本文件,因为我需要做更多的工作,无法放入heart:set_cmd/1中,所以我仍然调用heart:set_cmd(Dir++“/priv/myHeartScript.sh”++Arg1++“++++++”++Arg2),但不要因为Args的大小有限制而忘乎所以!我还使用在vm.args中使用-env设置的环境变量将数据传递给脚本,例如预加载程序路径/名称。这使我避免了在部署期间也必须编辑纸条

如果有人有更好的解决方案,请告诉我

更新

Erlang Solutions的团队非常友好,为这个问题提供了一些线索。基本上,他们知道没有人使用内置于分布式模型中的Erlangs。一切都围绕着数据,只要数据在冗余数据库上可用,您就可以随时启动新的应用程序。他们建议使用云主机,当一台服务器出现故障时可以启动新服务器,或者使用冗余节点设计,因此有5个节点并行运行,如果一些节点出现故障,您可以手动或通过其他方式重新启动它们

至于我,我可以说,用心开始一个预加载版本/应用程序可以完成任务,但它很快就会变得复杂。现在要启动该应用程序,需要设置几个额外的sys.config/vm.args/rebar.config文件。我将研究他们对下一次迭代的建议

更新

不再使用Erlang分布式模型。使用RabbitMQ将心跳发送到所有节点,包括其自身。如果一个节点从自身接收到心跳,而没有其他节点,那么它就是主节点,如果接收到多个心跳,那么使用任何属性(如节点名称)来选择主节点。您不必使用RabbitMQ,但需要确保所有节点都可以到达相同的目的地并从中消费


此外,德沃人反对使用心脏。他们更喜欢使用标准的Linux工具来监视应用程序状态,并在崩溃或服务器重新启动后重新启动它。

您能显示配置文件的内容吗?您的系统应该注意到主系统已经重新启动,它应该从辅助系统执行接管。你是否启用了
sasl
,或者你是否尝试过使用
observer
,这样你就可以看到更多关于发生了什么的细节了?嗨,史蒂夫,配置非常标准,启用了sasl,尽管它可能在我的应用程序之后启动,这可能是个问题,我必须检查一下。我不知道在这种情况下观察者会告诉我什么。我也注意到了心脏的一个大问题。当heart尝试重新启动主节点时,它会停止故障转移节点,在尝试失败后,它不会故障转移到机架