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

简介: 本文记录了一次线上应用发版时出现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
相关文章
|
Kubernetes 应用服务中间件 HSF
容器服务 kubernetes(ACK)中应用优雅上下线
容器服务 kubernetes(ACK)中应用优雅上下线
8034 0
|
消息中间件 Java Spring
RocketMQ-JAVA客户端不同版本接入方式
RocketMQ4.0 RocketMQ5.0 JAVA接入 spring springboot
RocketMQ-JAVA客户端不同版本接入方式
|
5月前
|
人工智能 开发框架 安全
浅谈 Agent 开发工具链演进历程
模型带来了意识和自主性,但在输出结果的确定性和一致性上降低了。无论是基础大模型厂商,还是提供开发工具链和运行保障的厂家,本质都是希望提升输出的可靠性,只是不同的团队基因和行业判断,提供了不同的实现路径。本文按四个阶段,通过串联一些知名的开发工具,来回顾 Agent 开发工具链的演进历程。
1078 78
|
5月前
|
SQL 人工智能 关系型数据库
AI Agent的未来之争:任务规划,该由人主导还是AI自主?——阿里云RDS AI助手的最佳实践
AI Agent的规划能力需权衡自主与人工。阿里云RDS AI助手实践表明:开放场景可由大模型自主规划,高频垂直场景则宜采用人工SOP驱动,结合案例库与混合架构,实现稳定、可解释的企业级应用,推动AI从“能聊”走向“能用”。
1220 41
AI Agent的未来之争:任务规划,该由人主导还是AI自主?——阿里云RDS AI助手的最佳实践
|
3月前
|
运维 监控 前端开发
基于AI大模型的故障诊断与根因分析落地实现
本项目基于Dify平台构建多智能体协作的AIOps故障诊断系统,融合指标、日志、链路等多源数据,通过ReAct模式实现自动化根因分析(RCA),结合MCP工具调用与分层工作流,在钉钉/企业微信中以交互式报告辅助运维,显著降低MTTD/MTTR。
3600 28
|
5月前
|
数据采集 人工智能 编解码
AI出码率70%+的背后:高德团队如何实现AI研发效率的量化与优化
本文系统阐述了在AI辅助编程快速发展的背景下,如何构建一套科学、可落地的研发效率量化指标体系
1555 27
AI出码率70%+的背后:高德团队如何实现AI研发效率的量化与优化
|
机器学习/深度学习 人工智能 自然语言处理
如何构建企业级数据智能体:Data Agent 开发实践
本篇将介绍DMS的一款数据分析智能体(Data Agent for Analytics )产品的技术思考和实践。Data Agent for Analytics 定位为一款企业级数据分析智能体, 基于Agentic AI 技术,帮助用户查数据、做分析、生成报告、深入洞察。
|
5月前
|
人工智能 安全 开发工具
C3仓库AI代码门禁通用实践:基于Qwen3-Coder+RAG的代码评审
本文介绍基于Qwen3-Coder、RAG与Iflow在C3级代码仓库落地LLM代码评审的实践,实现AI辅助人工评审。通过CI流水线自动触发,结合私域知识库与生产代码同仓管理,已成功拦截数十次高危缺陷,显著提升评审效率与质量,具备向各类代码门禁平台复用推广的价值。(239字)
1183 24

热门文章

最新文章