问题描述
我有两个在集群中运行的 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 时添加延迟:
- 在收到
SIGTERM
时设置服务延迟(例如 15 秒),以便在延迟期间像往常一样继续响应请求。 - 使用 Kubernetes
preStop
挂钩在容器上执行sleep 15
命令。这允许服务在 Kubernetes 更新其端点的 15 秒期间继续响应请求。当SIGTERM
挂钩完成时,Kubernetes 将发送preStop
。
这两种解决方案都会给 Kubernetes 一些时间来将更改传播到其内部组件,以便流量停止路由到被删除的 pod。
这个答案的一个警告是,我不熟悉 Hazelcast Clustering 以及您的特定发现模式是如何设置的。