防止在所有当前请求完成之前关闭Spring Boot应用程序

时间:2019-05-17 15:42:40

标签: java spring-boot docker kubernetes spring-boot-actuator

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

当我们通过将映像设置为最新版本来更新部署时,吊舱会被破坏,新的吊舱会旋转。我们的服务可满足新要求。但是,当前的请求可能并且确实会被切断,这对于下载非常大文件的客户端来说很烦人。

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

这是我们在Spring Boot应用程序中尝试过的内容:

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

  • 通过实现HttpSessionListener并重写sessionCreated/Destroy方法来更新计数器来对活动会话进行计数。之所以失败,是因为这些方法没有在单独的线程上调用,因此始终在关闭侦听器中报告相同的值。

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

编辑:我们管理群集,因此我们仅尝试通过修改的Pod规范

在部署的托管更新中减轻当前连接的客户端的服务中断

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

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

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

请注意,因为我们是从监视脚本向pid 1发送TERM的,所以pod会在此时终止,并且终止GracePeriodSeconds永远不会被命中(这是预防措施)

这是脚本:

#!/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

这是新的广告连播规范:

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

答案 2 :(得分:0)

尝试优雅关闭您的Spring Boot应用程序。

这可能有帮助:

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

此实现将确保您没有任何活动连接被杀死,并且应用程序会在关机之前正常地等待它们完成。