繁体   English   中英

防止 Spring Boot 应用程序关闭,直到所有当前请求完成

[英]Prevent Spring Boot application closing until all current requests are finished

我们有一个 Spring Boot (2.0.4) 应用程序公开了许多端点,其中一个使客户端有时可以检索非常大的文件(~200 GB)。 该应用程序通过配置了滚动更新策略的 Kubernetes 部署在 Pod 中公开。

当我们通过将映像设置为最新版本来更新我们的部署时,pod 会被破坏,新的 pod 会启动。 我们为新请求提供无缝服务。 然而,当前的请求可以而且确实会被切断,这对于正在下载非常大的文件的客户端来说可能会很烦人。

我们可以在我们的部署规范中配置 Container Lifecycle Pre-Stop hooks 以在通过它的 PID 向应用程序发送关闭信号之前注入暂停。 这有助于防止任何新流量进入已设置为终止的 pod。 有没有办法暂停应用程序关闭过程,直到所有当前请求都完成(这可能需要几十分钟)?

以下是我们在 Spring Boot 应用程序中的尝试:

  • 实现拦截ContextCloseEvents的关闭侦听器; 不幸的是,我们无法可靠地检索活动请求列表。 在关闭过程的这个阶段,任何可能有用的执行器指标都不可用。

  • 通过实现HttpSessionListener和覆盖sessionCreated/Destroy方法来更新计数器来计算活动会话。 这会失败,因为这些方法不是在单独的线程上调用的,因此始终在关闭侦听器中报告相同的值。

我们应该尝试其他任何策略吗? 从应用程序本身或容器内部,还是直接通过 Kubernetes 资源描述符? 建议/帮助/指针将不胜感激。

编辑:我们管理集群,因此我们只是在通过修改后的 pod 规范对部署进行托管更新期间尝试缓解当前连接客户端的服务中断

您可以增加terminationGracePeriodSeconds ,默认为 30 秒。 但不幸的是,没有什么可以阻止集群管理员强制删除您的 pod,并且整个节点可能会因各种原因而消失。

我们结合了上述方法来解决我们的问题。

  • 将终止GracePeriodSeconds增加到我们期望在生产中看到的绝对最大值
  • 添加了 livenessProbe 以防止 Traefik 过早路由到我们的 pod
  • 引入了一个 pre-stop 钩子,注入一个暂停并调用一个监控脚本:
    1. 使用集群 Traefik 服务的外部地址监控与我们进程(pid 1)的已建立连接的 netstat
    2. 发送 TERM 到 pid 1

请注意,因为我们从监控脚本将 TERM 发送到 pid 1,因此 pod 将在此时终止,并且 terminateGracePeriodSeconds 永远不会被击中(这是作为预防措施)

这是脚本:

#!/bin/sh

while [ "$(/bin/netstat -ap 2>/dev/null | /bin/grep http-alt.*ESTABLISHED.*1/java | grep -c traefik-ingress-service)" -gt 0 ]
do
  sleep 1
done

kill -TERM 1

这是新的 pod 规范:

containers:
  - env:
    - name: spring_profiles_active
      value: dev
    image: container.registry.host/project/app:@@version@@
    imagePullPolicy: Always
    lifecycle:
      preStop:
        exec:
          command:
          - /bin/sh
          - -c
          - sleep 5 && /monitoring.sh
    livenessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 20
      timeoutSeconds: 3
    name: app
    ports:
    - containerPort: 8080
    readinessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 60
    resources:
      limits:
        cpu: 2
        memory: 2Gi
      requests:
        cpu: 2
        memory: 2Gi
  imagePullSecrets:
  - name: app-secret
  serviceAccountName: vault-auth
  terminationGracePeriodSeconds: 86400

尝试正常关闭你的Spring引导应用程序。

这可能有帮助:

https://dzone.com/articles/graceful-shutdown-spring-boot-applications

此实现将确保您的任何活动连接都不会被终止,并且应用程序将在关闭之前优雅地等待它们完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM