Vertx 集群事件总线不会删除 kubernetes 滚动部署上的旧节点

问题描述

我有两个在集群中运行的 vertx 微服务,并使用本地云中的无头服务 (link) 相互通信。每当我进行滚动部署时,我都会面临服务内的连接问题。当我分析日志时,我可以看到旧节点/pod 正在从集群列表中删除,但事件总线没有删除它并在循环的基础上使用它。

以下是部署前的成员组信息

    Member [192.168.4.54]:5701 - ace32cef-8cb2-4a3b-b15a-2728db068b80        //pod 1
    Member [192.168.4.54]:5705 - f0c39a6d-4834-4b1d-a179-1f0d74cabbce this
    Member [192.168.101.79]:5701 - ac0dcea9-898a-4818-b7e2-e9f8aaefb447      //pod 2

部署开始时,pod 2 从成员列表中删除

[192.168.4.54]:5701 [dev] [4.0.2] Could not connect to: /192.168.101.79:5701. Reason: SocketException[Connection refused to address /192.168.101.79:5701]
    Removing connection to endpoint [192.168.101.79]:5701 Cause => java.net.socketException {Connection refused to address /192.168.101.79:5701},Error-Count: 5
    Removing Member [192.168.101.79]:5701 - ac0dcea9-898a-4818-b7e2-e9f8aaefb447

并且添加了新成员,

Member [192.168.4.54]:5701 - ace32cef-8cb2-4a3b-b15a-2728db068b80
    Member [192.168.4.54]:5705 - f0c39a6d-4834-4b1d-a179-1f0d74cabbce this
    Member [192.168.94.85]:5701 - 1347e755-1b55-45a3-bb9c-70e07a29d55b  //new pod
All migration tasks have been completed. (repartitionTime=Mon May 10 08:54:19 MST 2021,plannedMigrations=358,completedMigrations=358,remainingMigrations=0,totalCompletedMigrations=3348,elapsedMigrationTime=1948ms,totalElapsedMigrationTime=27796ms)

但是当向已部署的服务发出请求时,尽管旧 pod 从成员组中删除,但事件总线使用旧 pod/服务引用(ac0dcea9-898a-4818-b7e2-e9f8aaefb447),

[vert.x-eventloop-thread-1] DEBUG io.vertx.core.eventbus.impl.clustered.ConnectionHolder - tx.id=f9f5cfc9-8ad8-4eb1-b12c-322feb0d1acd Not connected to server ac0dcea9-898a-4818-b7e2-e9f8aaefb447 - starting queuing

我查看了滚动部署的官方文档,我的部署似乎遵循文档中提到的两个关键事项,仅删除一个 Pod,然后添加了新的 Pod。

never start more than one new pod at once

forbid more than one unavailable pod during the process

我使用的是 vertx 4.0.3 和 hazelcast kubernetes 1.2.2。我的 Verticle 类正在扩展 AbstractVerticle 并使用,

Vertx.clusteredVertx(options,vertx -> {
                    vertx.result().deployVerticle(verticleName,deploymentOptions);

抱歉,帖子太长,非常感谢您的帮助。

解决方法

一个可能的原因可能是由于 竞争条件,Kubernetes 删除了 pod 并更新了 Kube-proxy 中的端点,如此详尽的 article 中所述。这种竞争条件将导致 Kubernetes 在 Pod 终止后继续向被删除的 Pod 发送流量。

一种TL;DR 解决方案是在通过以下任一方式终止 Pod 时添加延迟

  1. 在收到 SIGTERM 时设置服务延迟(例如 15 秒),以便在延迟期间像往常一样继续响应请求。
  2. 使用 Kubernetes preStop 挂钩在容器上执行 sleep 15 命令。这允许服务在 Kubernetes 更新其端点的 15 秒期间继续响应请求。当 SIGTERM 挂钩完成时,Kubernetes 将发送 preStop

这两种解决方案都会给 Kubernetes 一些时间来将更改传播到其内部组件,以便流量停止路由到被删除的 pod。

这个答案的一个警告是,我不熟悉 Hazelcast Clustering 以及您的特定发现模式是如何设置的。