灵雀与鲲鹏在中美两大展会上大放异彩, Manta上演拉斯维加斯、北京两城记
06-17
业务上云容器排查与思考 1 简介 此前,我们部门已经完成了业务上云的目标。然而,随着业务请求的激增,云应用系统也面临着挑战。
一些复杂的故障和挑战。下面,我将结合近期容器排查工作,与大家一起探讨如何优化系统的性能、可扩展性和容错性,为读者保证系统的高效运行和可靠交付提供参考。
2 业务异常及排查思路 用户反映任务出现异常,且长时间处于“进行中”状态;用户上传的源码大小约MB,预计半小时出结果,实际花了6个小时。没有一个任务已经结束。
异常任务2.1 排查思路 排查思路 通过上述排查思路和定位动作,最终定位到了根本原因:排查发现容器集群资源紧张,结合云原生组件kubeproxy反向代理机制,两者结合造成的造成的。下面详细列出分析思路和大致流程,一起讨论。
3 故障排查与定位 3.1 业务流程梳理 3.1.1 任务流程图 用户上传源数据包:用户可以上传自己的任务数据包,并配置任务执行所需的资源(如:执行算法、执行线程数等)。 ) APP1→APP2:上传任务数据任务进入APP2内部队列:传入任务优先进行数据分片处理 APP2→APP3:APP2分片处理完成后,按照可配置的请求数量,每批次发出T个请求线程 T. 将分片内容传输到 APP3 APP3:从磁盘 IO 读取开源知识库数据 APP3:对接收到的分片内容进行算法分析 APP3:请求中携带的分片数据全部分析完毕,全部正确响应给 APP2 ,声明:任务“完成” 3.1.2 分析 由于任务当前正在执行,则说明问题出在步骤(3)~(7),因此重点关注APP2 和APP3。
根据请求响应关系,APP2定位为客户端,APP3定位为服务器端。 3.2 容器进程分析 正常预期的现象是:两个容器都有业务进程,双方进程频繁通过HTTP进行通信;当任务执行完成后,双方进程都会退出并被系统销毁。
那么我们首先需要分析两边的容器进程。 3.2.1 通过 ps -ef 查看容器子进程,并分别在客户端APP2和服务端APP3上打印进程状态。
客户端APP2的任务进程:有一个进程存活,说明客户端进程卡住了。服务器端APP3任务进程:无正在执行的任务进程。
3.2.2 分析发现客户端APP2进程卡住,而服务端APP3进程正常结束。3.3 找出进程卡住的原因。
分析进程卡住的原因时,首先想到日志,然后想到网络。 3.3.1 检查容器日志。
查看云容器的日志,发现没有打印相关ERROR级别的日志,说明业务整体处于成功状态,因此怀疑是环境问题(网络/IO等资源)导致的。 3.3.2 使用netstat -ntp | grep PID 查看容器进程的网口状态,分别查看APP2和APP3进程关联的网口状态。
客户端容器进程网口状态 由于服务端没有工作进程,所以找不到关联的网口。 3.3.3 分析 通过网络排查,发现客户端APP2进程有4个TCP端口一直监听,没有正常关闭。
3.4 请求链路分析从客户端和服务器角度出发,定位异常TCP连接监控。 3.4.1 思路:从客户端APP2来看,进程被挂起的原因是:建立4个TCP连接后,TCP端口一直在等待数据响应(即客户端发起HTTP请求,一直处于等待状态)被阻止)。
在任务期间,进程可能会发起 > 请求。 ,最后剩余4个异常请求的TCP连接。
在步骤3.2.1中发现:客户端进程通过service-name请求服务端容器。从服务器APP3的角度来看,虽然计算工作量会很大,但服务器进程最终还是被正常销毁了。
3.4.2 请求链接 由于容器集群已经部署在云端,运行在 K8S 部署架构下,所以我和技术操作同学一起整理了如下请求链接: 这里的容器请求链接和 HTTP 普通的一样要求。响应的区别:由于service的“干扰”,kube-proxy实际上是一个代理层,负责实现service。
3.4.2.1 kube-proxy利用kube-proxy的ipvs机制实现service-ip到容器ip的映射,完成一个网络转发代理,最终实现容器之间的通信。 kube-proxy 的 ipvs 机制 3.4.2.2 实际转发请求请求链路最终经过以下三步: 当容器 APP2 发起请求时,首先通过 service-name 找到 APP3-service(service 是一层 proxy,暴露了pods 对外)请求然后由 kube-proxy 处理,实现虚拟 IP 转换(即 service-ip 到 pod 实例 ip 的转换)。
云上的kube-proxy采用ipvs代理模式,最终将流量引导到某个后端Pod(即APP3-pod)。流量转向完成后,请求最终会进入 pod 的一个实例(即 APP3-container) 3.4.3 分析 正如上面步骤 3.3.3 中也分析的那样,客户端连接(客户端 APP2 → APP3-service)始终是已确立的。
服务器连接(APP3-服务→APP3-容器)已关闭。然后我们判断问题出在kube-proxy代理上。
3.4.4 猜想验证 因为恢复业务使用一直是重中之重,所以我们基于对请求链路的理解,大胆测试一下:如果改成通过pod-ip/port直接通信,客户端进程是否可以正常结束?后续验证:该方案可行,此时客户端和服务端进程均正常结束。 3.4.4.1 临时解决方案是通过pod-ip/port直连。
同时,技术操作同学还协助完成pod重启后pod-ip的动态刷新,保证临时方案的可用性。目前,我们已优先恢复正常业务使用。
3.4.5 根本问题 然而,kube-proxy 的流量代理问题目前还没有明确定位;如果以后容器服务继续高可用部署的话,仍然离不开这个组件,所以我们会继续讨论。通过步骤3.4.3的分析,我们最终确定问题出在kube-proxy链路上,因此我们决定在客户端和服务器端都进行抓包。
3.5 抓包分析网络通过tcpdump,我们分别抓获了客户端和服务端的流量包(虽然日志很大,幸好分配给容器的磁盘空间足够,事后清理掉了),然后下载并用wireshark分析了网络情况。该过程有点繁琐,因为抓包过程需要顺序启动、客户端服务器进程重现、文件权限申请等细节,所以这里不再讨论抓包过程。
3.5.1网络分析最终重现了问题,对剩余的几个TCP连接进行了抓包分析。这里我们分析其中一个异常的TCP连接(客户端进程剩余TCP连接端口=2)。
3.5.1.1 连接建立点客户端client——连接建立客户端目标为service-ip,三向握手完成,12:03:06建立连接。服务器 - 通过 kube-proxy 与特定 pod 实例建立连接。
服务器与客户端的三次握手完成。连接于 12:03:09 建立。
3.5.1.2 故障异常点 客户端 客户端 - 故障 客户端最后一次在异常点与service-ip 通信时间为12:04:51。服务器端 - 故障异常点之间有30分钟的间隔。
服务器返回的最后一个数据包是在 12:35:20 发送回客户端的。由于客户端检测到连接存在问题,因此向服务器发送了一个数据包。
收到RST消息。 3.5.2 分析 通过网络抓包分析,发现客户端与服务建立连接,而不是直接与服务器建立连接。
30分钟后,服务器向客户端返回数据包。服务器可以直接将数据包返回给客户端。
但客户端显然没有识别出服务器的数据包,发起了断开连接请求(RST包),然后服务器TCP就正常关闭了。最后,“犯罪现场”出现了:客户端和服务之间的连接仍然存在,服务器TCP正常关闭。
3.6 kube-proxy代理配置自检时发现的线索是,服务器向客户端返回了一个数据包,造成了“犯罪现场”。于是我们请云老师帮忙排查问题,最终确定是kube-proxy的代理会话超时机制导致的。
3.6.1 kube-proxy 会话保活机制 kube-proxy 有会话保活机制:它会记录客户端和服务器之间的连接,有效期为 15 分钟。当ipvs会话保持超时状态时,连接记录就消失了。
连接记录的作用是什么?当客户端发送数据包时,发送到service-ip的数据包位于服务器IP中,然后转发到服务器。当服务器返回数据包时,发送给客户端的数据包会以service-ip的名称进行转发。
对客户端3.6.2的请求链路进行分析整理,得到如下“客户端-服务-服务器”三方通信流程图: 三方通信-请求链路“服务器向客户端返回一个数据包,并原因 我们看一下“犯罪现场”,重点关注上面的两个时间点: 第 15 分钟,kube-proxy 清理会话 第 30 分钟,服务器向客户端返回数据包:但是服务器返回了一个数据包。此时发往客户端的不再是通过service-ip的“标题加持”(因为会话记录被清除,服务器返回的数据包无法转换为原来的服务IP),而是数据。
数据包直接以服务端的名义丢失给客户端,此时客户端并不知道服务端(在k8s的服务机制下,客户端是不知道服务端信息的,因为永远都是服务。连接到客户端);因此,向服务端返回一个RST包;服务器收到RST包后,就知道客户端了,所以主动关闭自己这边的TCP端口; 【这说明:服务器进程正常关闭TCP端口】而客户端一直在等待,原来连接到自己的service-ip的返回包永远无法等待【本次分析:客户端始终无法关闭[TCP端口正常] 3.6.3 结论 至此,我们已经找到了失败的根本原因:因为客户端在客户端和服务器端建立连接后,请求被搁置,没有保持活动状态时间,导致 kube-proxy 清除会话记录;当服务器进程超时时,由于会话记录被清除,返回数据包出现异常,未进行处理。
将服务返回包交给客户端;客户端一直在等待的服务返回包无法等待,所以一直监听(对于业务来说,是一个挂起的进程)。调整 kube-proxy 的会话超时时间并不实际。
因为基础组件的变化具有全局影响,所以最后一个问题自然产生:为什么服务器来不及处理请求而无法及时保活?3.7 容器资源监控关于服务器为什么来不及处理请求,不能及时保活,我们想到两个原因:服务器计算能力有限,导致现有请求处理缓慢,新请求被阻塞(前者与Container资源配置密切相关,此项可优化)请求超时设置太长,给服务器处理超时的机会(这是由产品能力决定的,以保证服务器计算完全完成并且响应迅速,这一项没有太大的调整空间)基于服务器计算能力的评估,只能与容器资源限制有关,所以我检查了相关监控服务器APP3的CPU/内存/网络/IO。 3.7.1 CPU监控仅关注APP3,因为计算负载集中在该服务上。
监控显示CPU整体负载很低。当任务进行时,CPU占用率仅略有上升,然后下降(相当于不工作,说明APP2确实完成了计算工作)。
CPU3.7.2内存监控 监控显示:在APP3的数据分析过程中,内存一直在飙升,但一段时间后,数量有所下降。内存3.7.3 IO监控监控显示:APP3数据分析过程中,IO带宽已满,达到MBps,但一段时间后,监控下降。
因为我们采用云存储规格进行IO,也就是SSD,所以可以认为是性能瓶颈。云盘规格分析 3.7.4 从资源监控的角度来看,资源紧张是客观存在的:尤其是IO资源总是满的,内存也很紧张,这就暴露了容器的计算瓶颈在于资源;而CPU资源并没有增加,这也是由于资源利用率的限制,已经很高了; 4、运营策略的调整和思考要结合公司降本增效的背景,通过无限的资源投入来优化体验,片面追求更大的内存和更快的磁盘IO。
不切实际。这次独特的Bug排查也是由于业务流量增加引起的,所以我们决定利用好现有的条件来攻克难关: 分析流量增加的原因:首先我们找到了用户团队,了解了频率并承诺通过两种方式协助业务团队: 针对周期性业务调用压力:调整分布式任务,以时间换空间,避免短期资源高峰,降低系统负载压力。
去中心化确实是不可能的。通过合理配置并发任务数和线程数,可以提高任务执行效率,减少资源浪费,协助业务快速完成项目任务;优化技术架构:在资源有限的情况下,通过优化技术架构提高系统性能和稳定性。
后续我们将对容器集群的高可用架构和容器算法进行优化升级,以加快服务器的计算能力。我参加第二期腾讯科技创作特训营有奖征文分享万元奖池和键盘手表一块。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-18
06-18
06-18
06-17
06-17
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用