我最近一直在做一些关于 HA 模式下 Vert.x 和 Verticle 的行为的实验。我观察到 Vert.x 如何在各个节点上分配负载的一些弱点。
1.集群中的一个节点崩溃
想象一个配置有一些 Vert.x 节点(比如 4 或 5、10 等)的集群,每个节点都有数百或数千个 Verticle。如果一个节点崩溃,剩下的节点中只有一个会重启所有已经部署在崩溃节点上的 Verticle。此外,不能保证它将是部署的 Verticle 数量最少的节点。这是不公平的,在最坏的情况下,同一个节点会从之前崩溃的节点中获取所有的 Verticle,这可能会导致多米诺骨牌崩溃的情况。
2. 向负载较重的集群添加节点
将节点添加到负载较重的集群并不能帮助减少其他节点上的负载。现有的 verticles 不会在新节点上重新分配,新的 verticles 会在调用vertx.deployVerticle()
.
虽然第一点允许在一定限度内实现高可用性,但第二点打破了简单水平可扩展性的承诺。
我很可能是错的:我可能误解了某些东西,或者我的配置可能有问题。这个问题是关于确认这种行为以及你如何处理它或指出我的错误的建议。感谢您的反馈。
这就是我创建vertx
对象的方式:
VertxOptions opts = new VertxOptions()
.setHAEnabled(true)
;
// start vertx in cluster mode
Vertx.clusteredVertx(opts, vx_ar -> {
if (vx_ar.failed()) {
...
}
else {
vertx = vertx = vx_ar.result();
...
}
});
这就是我创建我的verticles的方式:
DeploymentOptions depOpt = new DeploymentOptions()
.setInstances(1).setConfig(prm).setHa(true);
// deploy the verticle
vertx
.deployVerticle("MyVerticle", depOpt, ar -> {
if(ar.succeeded()) {
...
}
else {
...
}
});
2019 年 12 月 25 日编辑:阅读 Alexey 的评论后,我相信我可能并不清楚。
通过承诺简单的水平可扩展性,我并不是说在插入新节点时重新分配负载很简单。我的意思是 Vert.x 向开发人员承诺,他需要做的就是让他的应用程序水平扩展很简单。Scale是 Vert.x 主页上的第一个参数,但是,您是对的,在仔细阅读之后,新添加的节点上没有任何关于水平缩放的内容。我相信我受 Elixir 或 Erlang 的影响太大了。也许 Akka 在 JVM 上提供了这个,但我没有尝试。
关于第二条评论,它不是(仅)关于每秒请求的数量。我在这里考虑的负载只是“什么都不做,等待消息”的verticles的数量。在进一步的实验中,我可以让这个 Verticle 做一些工作,然后我会发送一个更新。目前,想象一下在内存中代表实际连接的后端用户会话的长寿 Verticle。该系统在 3 个(或任何数量)集群节点上运行,每个节点托管数千个(或更多)会话/垂直。从这个状态开始,我添加了一个新节点并等待它完全集成到集群中。然后我杀死了前 3 个节点中的一个。所有 verticles 都可以正常重启,但只能在一个节点上重新启动,而且不能保证成为“空”的人。目标节点实际上似乎是随机选择的:我做了几次测试,我什至观察到所有被杀死节点的顶点在同一个节点上重新启动。在具有足够负载的真实平台上,这可能会导致全局崩溃。
我相信在 Vert.xa 中实现 verticles 的公平重启,即根据给定的负载度量(CPU、RAM、#of verticles,...)在所有剩余节点上分配 verticles 会更简单(不简单)而不是在新插入的节点上重新分配负载,因为这可能需要调度程序从另一个节点“窃取”verticles 的能力。
然而,在生产系统上,没有受到集群上某种公平分配工作负载的“保护”可能会导致大问题,并且由于 Vert.x 已经相当成熟,我对我的实验结果感到惊讶,因此认为我是做错事。