我们有一个Spring Boot(2.0.4)应用程序,它公开了许多端点,其中一个端点使客户端有时可以检索非常大的文件(约200 GB)。该应用程序通过配置了滚动更新策略的Kubernetes部署在Pod中公开。
当我们通过将映像设置为最新版本来更新部署时,吊舱会被破坏,新的吊舱会旋转。我们的服务可满足新要求。但是,当前的请求可能并且确实会被切断,这对于下载非常大文件的客户端来说很烦人。
我们可以在部署规范中配置Container Lifecycle Pre-Stop挂钩,以便在通过PID将关闭信号发送给应用之前注入暂停。这有助于防止任何新流量流向已设置为“终止”的Pod。有没有办法暂停应用程序关闭过程,直到所有当前请求都完成(这可能需要数十分钟)?
这是我们在Spring Boot应用程序中尝试过的内容:
实现关闭监听器,该监听器拦截ContextCloseEvents
;不幸的是,我们无法可靠地检索活动请求列表。在关机过程的此阶段,任何可能有用的执行器指标均不可用。
通过实现HttpSessionListener
并重写sessionCreated/Destroy
方法来更新计数器来对活动会话进行计数。之所以失败,是因为这些方法没有在单独的线程上调用,因此始终在关闭侦听器中报告相同的值。
我们应该尝试其他策略吗?从应用程序本身或容器中,还是直接通过Kubernetes资源描述符?建议/帮助/指针将不胜感激。
编辑:我们管理群集,因此我们仅尝试通过修改的Pod规范
在部署的托管更新中减轻当前连接的客户端的服务中断答案 0 :(得分:4)
您可以增加terminationGracePeriodSeconds
,默认值为30秒。但是不幸的是,没有什么可以阻止集群管理员强行删除您的Pod,并且有各种各样的原因可以使整个节点消失。
答案 1 :(得分:0)
我们结合以上方法解决了我们的问题。
请注意,因为我们是从监视脚本向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
此实现将确保您没有任何活动连接被杀死,并且应用程序会在关机之前正常地等待它们完成。