【问题标题】:Kubernetes pods graceful shutdown with TCP connections (Spring boot)Kubernetes pods 使用 TCP 连接优雅关闭(Spring boot)
【发布时间】:2020-06-02 05:01:03
【问题描述】:

我将我的服务托管在 azure 云上,有时我在没有任何明显原因的情况下得到“BackendConnectionFailure”,经过调查,在大多数情况下,我发现此异常与自动缩放(缩小)之间几乎同时存在相关性。

根据文档的终止宽限期默认为 30 秒,就是这样。 pod 将被标记为终止,负载均衡器将不再考虑它,因此不再接收请求。据此,如果我的服务花费的时间远少于 30 秒,我的应用程序中不需要 prestop 钩子或任何特殊实现(如果我错了,请纠正我)。

如果上一段是正确的,为什么这个异常发生的比较频繁?我的想法是当 pod 被标记为终止并且负载均衡器不再向 pod 转发请求时,它应该这样做。

编辑 1:

架构就是这样

客户端 -> 防火墙(azure) -> API(azure APIM) -> 微服务(Spring boot) -> 后端(第三方) 或 Azure RDB,具体取决于服务

我认为异常来自 APIM,我发现此异常有两种模式:

  1. Message The underlying connection was closed: The connection was closed unexpectedly. Exception type BackendConnectionFailure Failed method forward-request

Response time 10.0 s

  1. Message The underlying connection was closed: A connection that was expected to be kept alive was closed by the server. Exception type BackendConnectionFailure Failed method forward-request

Response time 3.6 ms

【问题讨论】:

  • 您能更详细地描述一下您的应用程序的架构吗? BackendConnectionFailure 来自哪里?什么与负载均衡器通信?您希望与应用程序的活动连接会发生什么?
  • @Matt:根据 k8s pod 终止“kubernetes.io/docs/concepts/workloads/pods/pod/…”负载均衡器将处于终止状态的 pod 移除。我希望即使在 pod 终止时连接也不会终止,我希望 pod 阻止进一步的请求,并在完成当前请求后关闭。
  • 你是如何向 APIM 公开 spring boot k8s 服务的?
  • @Matt,如果我理解你的意思,该服务托管在 azure k8s 上。 API通过后端url和“RequestMapping”路径访问服务。
  • 更具体地说,在 kubernetes 中,您使用什么来公开服务。可能是 ingress、loadbalancer、nodeport 之一。

标签: spring-boot kubernetes azure-aks horizontal-pod-autoscaling


【解决方案1】:

Spring Boot doesn't do graceful termination 默认情况下。

Spring Boot 应用程序及其应用程序容器(不是 linux 容器)可以控制终止宽限期内现有连接发生的情况。使用的协议以及客户端对“关闭”的反应也有一定的作用。

如果您到了宽限期结束,那么一切都会硬重置。

Kubernetes

When a pod is deleted in k8s,从服务中删除 Pod Endpoint 的同时向容器发送 SIGTERM 信号。

此时,集群节点将被重新配置,以删除任何将流量导向 Pod 的规则。到 Pod/容器的任何现有 TCP 连接都将保持连接跟踪,直到它们被关闭(由客户端、服务器或网络堆栈)。

对于 HTTP Keep Alive 或 HTTP/2 服务,客户端将继续访问同一个 Pod 端点,直到被告知关闭连接(或被强制重置)

应用

基本规则是,在 SIGTERM 上,应用程序应该:

  • 允许正在运行的事务完成
  • 是否需要进行任何应用程序清理
  • 停止接受新连接,以防万一
  • 尽可能关闭所有非活动连接(保持活动请求、websocket)

您可能无法处理的某些情况(取决于客户)

  • 在宽限期内未完成请求的保持活动连接无法获得Connection: close 标头。它将需要 TCP 级别的 FIN 关闭。
  • 传输时间长的慢速客户端,在一种 HTTP 传输方式中,这些必须等待或强制关闭。

虽然 keepalive 客户端应该遵守 TCP FIN 关闭,但每个客户端的反应都不同。 Microsoft APIM 可能很敏感并会产生错误,即使没有对现实世界产生影响。最好在扩展时对您的设置进行负载测试,以查看是否对现实世界产生影响。

更多spring boot信息见:

https://github.com/spring-projects/spring-boot/issues/4657 https://github.com/corentin59/spring-boot-graceful-shutdown https://github.com/SchweizerischeBundesbahnen/springboot-graceful-shutdown

【讨论】:

    【解决方案2】:

    如果需要,您可以使用 preStop 睡眠。虽然 pod 会立即从服务端点中删除,但端点更新仍需要时间(10-100 毫秒)才能发送到每个节点并让它们更新 iptables。

    【讨论】:

    • 据我了解,prestop 挂钩将在容器级别运行,“睡眠”的预期行为是什么?以及在 iptables 更新之前它将如何阻止接收请求。
    【解决方案3】:

    当您的应用程序收到 SIGTERM(来自 Pod 终止)时,它需要首先停止报告它已准备好(readinessProbe 失败),但仍会在来自客户端的请求时提供服务。一段时间后(取决于您的readinessProbe 设置),您可以关闭应用程序。

    对于 Spring Boot,有一个小型库可以做到这一点:springboot-graceful-shutdown

    【讨论】:

    • 我认为该项目更基于 openshift,这不是 Pod/Service termination 流程在 Kubernetes 上的工作方式。
    • OpenShift 是一个 Kubernetes(它只是一个类似于 GKE 或 Rancher 2 的发行版)。这个库有效 - 我们在生产中使用它。
    • 对不起,我在想 Openstack... 您是否发现正常 pod 终止过程有问题提示您使用该项目?似乎他们正在为 k8s 已经做的事情设计一个解决方案。
    猜你喜欢
    • 1970-01-01
    • 2019-09-26
    • 2018-12-23
    • 1970-01-01
    • 2011-08-07
    • 2021-10-28
    • 1970-01-01
    • 2010-11-23
    • 2018-01-07
    相关资源
    最近更新 更多