查看原文
其他

两个流程链路问题的排查和总结

编程一生 编程一生
2024-08-10

乱码问题


现象

在一类简单的业务场景下发起http请求的测试案例,返回的时候会100%有乱码。如果跳过跟厂商定制的7层负载均衡设备,直接连后端一台机器,则100%无乱码。在其他测试场景,则100%无乱码。


注意,此处的100%是那段时间实际发起请求的情况中乱码的占比,与SLA无关。

大家猜一猜,产生乱码的原因在哪一层?


处理过程

首先自证清白,我负责处理1。直连是无乱码的。其他场景是无乱码的。代码和线上稳定运行的版本是一套,线上是无乱码的。这个场景和其他场景唯一不同的是返回数据的模板是放在测试数据库中的。所以我将测试库中的模板换成其他无乱码场景的数据(避免编码问题,直接拷贝),仍然不起作用。将模板数据改成12,也能返回一个乱码。所以乱码应该是和[处理1]程序无关。


与自己这边无关,再看是上游的问题还是下游的问题?


下游[处理2]是新逻辑,像SSL和处理3都是线上稳定运行的。但是从日志里看,通过[处理1]的时候还不是乱码,只是回到发起端才有乱码的,说[处理2]有问题不合逻辑。


上游[跟厂商定制的7层负载均衡设备],因为有两个场景的对比,所以还是有理由找负责的同事查一查的。他们调查的结果是没有地方进行编码转换。


再往上游[案例发起端],要证明和案例发起模拟程序本身有没有关系。因为是http请求我采用直接将请求头和body使用在其他服务器上使用curl模拟请求的方式,结果与案例平台的结果一致:使用7层负载均衡设备会有乱码,不使用则无乱码。看来与模拟程序本身无关。


我们团队内部也有一个模拟工具,可以模拟请求,将http请求的body体复制进去,无论是否使用7层负载均衡设备都没有乱码。


我们团队内部模拟工具和案例发起端的区别 应该在请求头上。这时我注意到了http请求头的参数,里面有accept-encoding: gzip, deflate, br 。将这个参数去掉,果然无论是否使用7层负载均衡设备都没有乱码。


分析

通过处理过程,了解到问题原因是如果设置了accept-encoding: gzip, deflate, br。返回的数据在7层负载均衡设备会有处理。导致乱码。我看了他们的官网,使用的设备是支持gzip压缩解压的。

我猜测是它将没有加密的请求作为gzip解密处理了。找到7层负载均衡设备厂商的技术支持。已经将问题反馈给他们,请他们确认是根据哪个请求参数来确认是否加解密的。


这个问题更合理的步骤应该是这样:


乱码问题核心是要确认引起乱码的变量:有可能是一个参数,也有可能是一个系统内部问题。


使用案例平台发起请求乱码,然后使用我们团队内部模拟工具发起相同的请求不是乱码。这样可以定位和案例平台的某个变量有关系。变量分为参数和系统。使用curl代替系统自动发起来验证是否和系统有关。


使用curl模拟案例平台的请求乱码。使用curl模拟我们团队内部模拟工具发起相同的请求不是乱码。确认和系统无关,问题在参数上。


找到两个请求参数的差异,其中一个差异在accept-encoding上,并且这个参数和编码有关。调整这个参数,确认相关性。


socketTimeOut问题


现象

测试案例发起端和执行程序分布在两个机房,有防火墙。已经请网络组的同事将链路中的机器对应端口的防火墙打开。但是发起的请求,有大约80%可以正常执行返回结果。另外20%直接返回socketTimeout,在[处理1]上确认,并没有收到请求。


大家猜一猜,问题出在哪一个环节?


处理过程

首先自证清白,我负责处理1。从日志上看没有收到请求并不能证明请求没有到达,因为有可能是在请求在排队,没有到达处理环节就直接被丢弃了。因为用的是jetty,所以首先调大work线程数。再次发起请求,失败比例没有变化。用top命令查看cpu、mem使用都很低。运行中线程数远远低于设置的work线程数阈值。调大jvm内存再次发起请求,失败比例没有变化。所以socketTimeout的请求应该没有到达[处理1]。


如果[处理1]没有收到,则一定不是下游的问题。要向前来排查。在之前没有经过防火墙的时候,并发量更大的情况下,都可以正常处理,应该与7层负载均衡设备无关。


再看防火墙这一层,部分请求不正常,是否是限流造成的?搜索了一下防火墙的相关文档,防护墙是可以配置限流策略的。所以咨询了配置防火墙的同事,回复说没有限流策略。


再往前看发起端。查到发起端共10台机器。用linux命令grep socketTimeout | wc -l 发现异常主要集中在其中两台机器上。将请求数和socketTimeout数做对比,发现这两台机器都是失败的。并且这两台机器与其他机器是不同的网段。


禁用了有问题的两台机器,问题解决。


分析

通过处理过程,问题已经很清楚了。部分网段网络不通。这个问题的更合理的排查步骤应该是这样:


案例发起时返回socketTimeout,那先要判定到底是什么问题。因为socketTimeout有两种可能。一种是网络不通,一种是等待超时。如果从找出问题根因这个角度出发,从一开始就应该先看案例发起的机器与连接方网络是不是通的。如果使用的是ansible运维工具,可以用下面命令批量查看

ansible -i  hosts XX -m shell -a "curl http://XXXX:8080/健康检查接口 --connect-timeout 5"

这样很快就能诊断出问题原因。


总结反思

在两个问题的处理过程一开始,都是以自证清白开始的,而不是以解决问题开始的。我在反思这个思路是不是存在格局上的问题。


之所以以自证清白开始,是出于两方面的考虑。第一,吃过亏。我之前总是解决问题就好,把问题查清楚了,但是本着有问题大家一起担的原则,结果很多问题责任都被算在我们团队身上。这样会造成我们团队总有问题的表象。第二,我也刚做这个项目,很多环节并不清楚。对最终能不能解开这个问题也没有信心。所以至少要证明自己团队没有问题。


先来分析一下自己的两点考虑是否是正确的思路。对于第一点,达则兼济天下,穷则独善其身。首先需要先让别的团队对我们团队建立信任。如果不是我们团队的问题,是一定需要明白的表述清楚的。有个词叫:现实理想主义者,看网上意思说要胸怀理想,但是接受现实。用在这件事上,我理解就是自己心怀着有问题是大家一起的问题,一起解决就好这是对的理念,是要坚持的。但是为了实现正确的理念,方法是问题事实结论还是要摆清楚。让别人对自己或自己团队建立信任和影响力。


对于第二点,我所谓的自证清白实际上不能证明清白。这两个问题,特别是第一个问题,据说在我来这边之前很久了,一直没能解决。很大一个原因是大家都认为自己这边没有问题,所以就不管了。所谓的没有问题有可能是自己的知识盲区,只有真正找到唯一的真相,才能证明清白。

所以总的来说要做到两点:第一:一开始就要以查清楚问题为目标。第二:查清楚问题之后要把结论让大家知道,建立好自己团队的形象。


这个认知的明确和排查问题的快慢有直接的关系。如果两个问题不是从先看自己的部分开始向外辐射,就能运用更科学的流程来解决,速度会更快。如果一开始就以整体大局的思路来看问题,在整个链路上花的时间会更均匀,而不是偏重于自己负责的项目。对整个链路的理解会更清晰深刻。这也是格局对人的结果产生重大影响的原因之一吧。


继续滑动看下一个
编程一生
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存