记一次应用优雅下线排查经历

简介: 本文记录了一次线上应用发版时出现500错误的排查过程。问题出现在滚动更新过程中,部分请求调度到了正在下线的Pod,导致500错误。通过增加PreStop Hook、调整TerminationGracePeriodSeconds以及配置Java应用的优雅下线,最终解决了问题。此外,还发现SLB的长连接问题,并通过配置SLB优雅下线彻底解决了请求失败的情况。

1. 背景

最近和同事一起排查了下发版时应用会出现500错误的异常,感觉还是挺有意思的,这里做下记录,以便后续遇到问题时进行翻阅。

2. 问题状况

我们线上环境是使用的ack集群,发版时应用service对应的deployment下的pod会进行滚动更新,这种情况下会出现部分接口报500错误,初步判断是有请求调度到了正在下线中的pod,即Terminating状态,这样导致这部分请求出现报错。

3. 排查经过

出现这种问题时,已经考虑到是没做好优雅下线的问题,于是去网上搜了一下解决方式,做好java程序的优化下线,主要要做以下两件事情:

  1. 容器关闭时增加前置处理,让容器先不进行关闭操作,这样给k8s留出时间去修改服务的路由分发规则,同时增加容器优雅关闭时间 terminationGracePeriodSeconds,留出更多的时间供容器关闭。
  2. 应用内做好优雅下线设置。

3.1 容器配置修改

3.1.1 pod被删除原理

deployment下pod被删除时,会触发两条路径进行操作:
Pod层面

  1. Pod被删除会被置为Terminating状态
  2. Kubelet捕捉到Pod的变化,执行syncPod动作
  3. 如果Pod设置了PreStop Hook,会先执行PreStop Hook
  4. kubelet 对 Pod 中各个 container 发送调用 cri 接口中 StopContainer 方法,向 dockerd 发送 stop -t 指令,用 SIGTERM 信号以通知容器内应用进程开始优雅停止。
  5. 等待容器内应用进程完全停止,如果容器在 gracePeriod 执行时间内还未完全停止,就发送 SIGKILL 信号强制杀死应用进程(容器运行时处理)。
  6. 所有容器进程终止,清理 Pod 资源。

网络层面

  1. Pod 被删除,状态置为 Terminating。
  2. Endpoint Controller 将该 Pod 的 ip 从 Endpoint 对象中删除。
  3. Kube-proxy 根据 Endpoint 对象的改变更新 iptables/ipvs 规则,不再将流量路由到被删除的 Pod。
  4. 如果还有其他 Gateway 依赖 Endpoint 资源变化的,也会改变自己的配置(比如 Nginx Ingress Controller)。

具体关闭过程如下图所示:
image.png
通过上图可以得知,我们可以通过设置PreStop来sleep一定的时间,让网络层面有时间去修改路由规则,这样在pod关闭的时候,不会有请求进入,以避免出现问题,这也是优雅下线的主要设置。
因为TerminationGracePeriodSeconds是整个Pod的优雅下线等待时间,默认为30s,现在增加了PreStop执行时间后,TerminationGracePeriodSeconds时间也要进行相应的增加。

3.1.2 容器配置修改

修改deployment配置,进行以下操作:

  1. 增加PreStop Hook,在pod停止前sleep 30s,给k8s预留pod删除后修改endpoint中端点和iptables时间,使请求不会路由到正在关闭中的Pod上。
    image.png

  2. 增加TerminationGracePeriodSeconds到60s,因为有30s分给了PreStop Hook,所以将TerminationGracePeriodSeconds从30s改到60s。
    image.png

3.2 java应用内配置优雅下线

Spring Boot中启用优雅下线可以在配置中配置以下内容:

server:
    shutdown: graceful

spring:
    lifecycle:
         timeout-per-shutdown-phase: 30s

通过使用上述配置,Spring Boot 保证在收到 SIGTERM 后不再接受新请求,并在超时内完成所有正在进行的请求的处理。即使无法及时完成,也会记录相关信息,然后强制退出。对于 timeout 的值,应参考处理请求的最大允许持续时间。
这里可以看到,主要还是说正在进行的请求要预留时间进行处理,对于不接受新请求,如果前面路由没有正确修改,还是会有请求进来,只是被拒绝连接,这个请求一样没得到正确处理。

3.3 SLB长连接问题

经过前两项修改以后,进行了尝试,本来以为会没有500错误了,结果还是有错误出现,这里我以为是PreStop里sleep时间不够,于是就改大该时间到150s,发现还是不行,排查到这里有点没思路了,因为按前面的原理分析,这个优雅下线应该是没问题的了。这时候突然想到之前看过k8s的书,里面有关于Pod优雅关闭的描述,里面有提到Pod下线后,网络路由的修改并不会影响已有连接,也就是说虽然上面的设置会让新的连接指向新的Pod,但已有连接并不会改变,于是猜测是这个原因导致的,但怎么解决呢,当时并没有太多的思路。
后面同事查到SLB也可以进行优雅下线设置,进行设置后解决了问题,这里也印证了之前的想法是对的,就是已有连接导致的请求失败,只是当时不知道已有连接怎么设置断开,SLB设置优雅下线的方式为增加如下注解。
image.png
这个配置代表开启slb优雅下线,并且排空超时时间为30s,连接排空超时指定了在负载均衡器停止接收新连接之前,它将保持现有连接的时间。这个时间段内,负载均衡器会依旧允许现有的会话继续活动,从而为正在处理的请求争取时间,使其能够完成。
可以理解为负载均衡上已有连接在Pod已经是Terminating状态的情况下,会允许长连接再保持一段时间,用来处理已有请求,和应用内优雅下线处理类似。

4 总结

应用未优雅下线这个问题,前期根据网上信息进行设置,还是比较容易理解和配置的,但配置完了之后发现并不生效,这个时候由于缺少中间链路的日志信息,并不太清楚请求是落到哪个Pod导致的超时,所以导致排查一度比较困难和没有思路。当时虽然猜到了已有长连接可能存在影响,但不是特别确定,并且对怎么停掉之前的长连接不是特别有思路,要不然可以更快的解决问题,后续遇到这种还是应该沿着自己认为的方向接着去探索。

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
前端开发 应用服务中间件 Linux
Gin-Vue-Admin 线上部署
Gin-Vue-Admin 线上部署
1590 0
Gin-Vue-Admin 线上部署
|
Kubernetes 应用服务中间件 API
5 分钟了解 Kubernetes Ingress 和 Gateway API
5 分钟了解 Kubernetes Ingress 和 Gateway API
2540 0
|
存储 缓存 Kubernetes
在K8S中,Pod优雅终止过程是什么?
在K8S中,Pod优雅终止过程是什么?
|
存储 Kubernetes 网络协议
还不会 Cert Manager 自动签发证书?一文掌握
本文将介绍如何使用 Cert Manager 实现自动签发证书并与 Rainbond 结合使用。
|
存储 前端开发 Java
Git 仓库越来越大?不要慌!试试这个简单方法,轻松秒瘦身
Git 仓库越来越大?不要慌!试试这个简单方法,轻松秒瘦身
|
Kubernetes 异构计算 容器
Kubelet之Topology Manager分析
Topology Manager是kubelet的一个组件,在kubernetes 1.16加入,而kubernetes 1.18中该feature变为beta版。本篇文档将分析Topology Manager的具体工作原理。1.为什么需要Topology Manager现代计算机的CPU架构多采用NUMA(Non-Uniform Memory Access,非统一内存)架构。NUMA就是将cpu
5504 0
|
Kubernetes 监控 Cloud Native
|
Kubernetes Cloud Native 微服务
微服务实践之使用 kube-vip 搭建高可用 Kubernetes 集群
微服务实践之使用 kube-vip 搭建高可用 Kubernetes 集群
915 1
|
弹性计算 编解码 Cloud Native
全景剖析阿里云容器网络数据链路(二)—— Terway ENI
本文是[全景剖析容器网络数据链路]第二部分,主要介绍Kubernetes Terway ENI模式下,数据面链路的转转发链路。
1835 7
全景剖析阿里云容器网络数据链路(二)—— Terway ENI