我有一个标准情况,两个分布式Erlang节点,一个主节点备用.
当我停止主设备时备用设备启动 - 故障转移,当我启动主设备时备用设备停止 - 接管.只要没有打开心脏并且没有网络分裂,一切正常.
但是,当我在60秒左右断开主站与网络连接后,备用数据库会给我一个错误消息**删除(超时)连接**并启动,就像主节点停止一样.这对我来说很有意义,它不知道主服务器是否存活,并且epmd无法连接到主节点,因此它将从nodes()列表中删除.让我们假装这是理想的结果.
问题是,当连接恢复时,我同时运行主服务器和备用服务器,并且备用服务器无视主服务器正在运行的事实.在主服务器初始化期间ping备用数据库并不能解决问题.我检查了备用数据库上的nodes(),它看到主节点但仍然继续运行.
我现在的解决方案是创建一个进程,监视层次结构中每个节点上方的所有节点,如果其中任何一个在线,可以ping通,进程调用erlang:halt()来终止备用节点.它适用于简单的情况,但也许有人可以告诉我是否有更好的方法?我在Elixir论坛上发现了一个类似的问题,所以它可能是一个已知的erlang问题而没有一个简单的解决方案.https://elixirforum.com/t/distributed-application-network-split/10007
如果在网络拆分期间你不想让两个节点并行运行我猜测需要使用外部监控应用程序吗?
第二个主要问题是心脏.如果启用了heart,则不会发生故障转移.如果heart在调用start之前正在运行,则在调用应用程序启动时会停止故障转移节点.因此,即使它无法启动主服务器,例如,它也无法访问重要资源,它会停止故障转移节点,并且在启动主服务器失败后不会将其恢复.我不知道心脏是否应该与分布式应用程序一起使用,或者是否有一个选项可以在尝试启动节点之前和停止故障转移节点之前运行一些erlang代码来检查资源是否可用?
关于内心的文件不是很好.很难找到任何HEART_COMMAND的例子.我找到了一种方法来将HEART_COMMAND设置为我的应用程序中的脚本,但是参数可以有多长时间,并且它不会像文档中所说的那样长.例如,这会在再次调用应用程序启动之前将睡眠定时器设置为60秒.它没有解决任何问题,因为在60秒内它会停止故障转移节点并在主节点无法启动时挂起.
heart:set_cmd("sleep 60; ./bin/myapp start")
我现在最终解决的解决方案是让主要版本的核心开始另一个版本,一个预加载器,它初步检查所有资源是否可用,如果是,它启动主要的发布应用程序,如果他们不是它继续永远检查.这样主应用程序就可以在故障转移节点上运行而不会中断.所以主要版本已经开启,而预加载器则没有.我最终使用了一个bash脚本文件,因为我需要做的工作比我心里所能做的更多:set_cmd/1,所以我还在调用heart:set_cmd(Dir ++"/priv/myHeartScript.sh"++ Arg1 ++""++ Arg2),但是由于尺寸有限制,所以不要随意使用Args!我还使用了环境变量,我在vm.args中使用-env将数据传递给脚本,例如预加载器路径/名称.这使我可以避免在部署期间编辑脚本.
如果有人有更好的解决方案,请告诉我.
UPDATE
Erlang Solutions的团队非常友好地阐述了这一主题.基本上,他们所知道的任何人都不会使用分布式模型中构建的Erlang.一切都围绕着数据,只要它在冗余数据库上可用,您就可以随时启动新的应用程序.他们建议使用可以在新服务器停机或使用冗余节点设计时启动新服务器的云主机,因此并行启动5个节点,如果少数节点停机,您可以手动或通过其他方式重新启动它们.
至于我,我可以说,开始预加载器发布/应用程序的心脏完成工作,但它很快就变得复杂.要立即启动应用程序,需要配置几个额外的sys.config/vm.args/rebar.config文件.我将研究他们对下一次迭代的建议.