一次Feign超时引发的血案:生产环境故障排查全记录

你好,我是悟空。

背景

在一个风和日丽的下午,我正在享受着敲代码带来的的心流体验,突然生产那边的同事告诉我有一台设备无法正产生产,这种情况偶尔也会遇到,一般都能很快解决,但这次不同。下面是设备和生产系统简化后的交互示例图。

现在的现象是因某种异常原因导致设备不断重试发送请求,所以一直卡在生产中,不能生产成功。如果设备正常接收响应且设备能正常处理响应,就能生产成功。

排查记录

初步排查

先看日志,Kibana 上一顿操作猛如虎,根据设备的生产任务信息找到了相关的日志,找相关的研发一起看了下,业务逻辑都是按照正常逻辑做的,生成的数据也是正常的,这就有点奇怪了。

是不是有些日志没搜全呢?用 trace id 把整个链路的日志一起查出来看下,果然发现了一点端倪:系统在处理完请求后报了一个错,跟业务代码无关,看起来是一个网络问题。报错信息如下:

scss 复制代码
Controller未处理异常-Broken pipe
--sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
--sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:51)

丢给 AI 工具看下异常信息是啥。

"

"Broken pipe" 是一个常见的网络错误,通常表示尝试向一个已经关闭的管道(pipe)或套接字(socket)写入数据。这个错误在 Java 网络编程中也很常见,尤其是在使用 NIO(New Input/Output)库时。

可能的原因

  1. 客户端断开连接:客户端可能在服务器尝试写入数据之前关闭了连接。
  2. 网络问题:网络中断或不稳定可能导致连接断开。
  3. 服务器端问题:服务器可能在尝试写入数据时关闭了连接。
  4. 资源限制:系统资源不足,如文件描述符用尽,可能导致写入失败。

从这个报错上看,可能是偶发的网络问题,让生产人员重新生产下。尝试重新生产,依旧不行。

会不会是设备问题呢?因为该产品是第一次在生产环境上生产,之前也经常遇到设备问题导致无法正常生产的问题,而其他产品生产时都没有遇到这个问题。

推测是整个生产流程中的第③步设备接收响应时出了问题:

因查看设备的生产日志非常不便,所以采取以下方式:

  • 生产那边用其他可替代的设备来生产,反馈没有。
  • 将设备拿回中试再生产下,反馈生产成功。(中试:产品正式发布前需要在中试环境验证后才能生产)

另外我还将两套环境下生成的数据做了下对比,也没有发现问题。

排除法,锁定系统问题

用排除法,我们可以推测设备是正常的,那就一定是生产系统那边的问题,还是得继续看日志。

正好最近在看法医秦明的《燃烧的蜂鸟》,里面讲到了很多痕迹检验的技术、思路、心态。看日志不就是找痕迹么,看看有什么线索。

再用 trace id 搜索相关日志,确实发现了一些问题。在很多正常的业务日志中掺杂了一条超时日志:

这条日志说的是 Feign 客户端超时了,也就是说上游微服务超时了,关闭了连接,但是下游微服务还在正常执行业务逻辑,所以最后一条 Broken pipe 就是因为上游微服务关闭了连接才抛出来的。

如下图所示,第④步上游服务超时了,下游服务还未执行完,上游服务就返回异常结果给设备了。

我们再来看最开始的流程图,第②步处理请求超时了,没有返回正确的响应,导致设备不能正常生产。

为什么之前没找到日志

这个问题已经形成了闭环,再来回顾下之前为什么没看到这条日志,我复盘了当时的思路:

  • 只根据业务关键字来搜索日志,发现业务都是正常的,根本就没有 Feign 超时的日志。
  • 没有搜索 ERROR 级别的日志。
  • 虽然有根据 trace id 来查看日志,但因为之前认定业务逻辑都是正常执行的,没有想过系统内部会出现问题,所以很多日志都没有细看。

如果按照下面格式(trace id + ERROR)来搜索,就一定能发现关键的 feign 超时日志了。后续需要注意这个搜索技巧。

为什么 Feign 超时了?

这个超时问题,用 Kibana来排查就比较难了,得有一款监控下游微服务中到底执行了哪些逻辑,哪些地方比较耗时。恰好我们系统中部署了 Skywalking,查看性能问题它就是扛把子的。

重现问题

我测试调用了一下线上接口,然后用 Skywalking 查找最近比较耗时的接口,就能找到调用的接口,总共耗时 20s,其中阶段 S2 耗时 8.5s。如下图所示:

下游服务的接口耗时 20s,而 Feign 设置的是 10s 超时,所以上游微服务抛出了 Feign 超时的错误。

阶段 S2 问题

在阶段 S2 中,执行了一条比较耗时的 SQL 语句,我们可以从 Skywalking 上看到执行的 SQL 语句,如下图所示:

简化后的 SQL 语句如下,语句的意思是批量更新 p 字段相等的数据,将逻辑删除字段del_flag更新为1。

sql 复制代码
update  table_c c set c.del_flag = 1 where c.p = ?

这个语句看起来也没什么问题,p 字段是有索引的。但是你把这段 SQL 语句换成 SELECT 语句查下有多少条就会发现有很大的问题,居然查出了17000 条数据,那做 update 语句就比较耗时了。

这么多数据是怎么产生的呢?因为之前生产的时候,设备不断重复调用接口,插入了很多数据,然后又被这条语句逻辑删除了。

解决方案

加一个 where 条件就行,c.del_flag = 0

sql 复制代码
update  table_c c set c.del_flag = 1 where c.p = ? and c.del_flag = 0

阶段 S1 问题

解决了第一个耗时问题后,还有一个耗时问题,出现在 S1 阶段。我们接着往下看。

可以从 Skywalking 中看到重复调用了接口 C 很多次,如下图所示:

通过统计可以看到,在阶段 S1 中,系统总计 133 次重复调用了另外一个微服务的一个接口 C,平均一个耗时 80ms,总共耗费10s,如下图所示:

找相关的研发同学看了下之前写的代码,简化后的代码如下:

c 复制代码
list.stream().map(vo -> {
    调用接口 C
}

因为 list 里面有 133 项,所以重复调用了接口 C 133 次。

解决方案比较简单,如果调用接口 C 的参数一样,则可以提到外面,调用一次就行;如果参数不一样,可以用缓存,而不是调用接口。

好了,这两个阶段的问题修复后,设备就能正常生产了。

为什么之前没遇到这个问题

代码中有些逻辑没有走到调用 C 接口的 S1 阶段,所以下游服务的接口不会超时。

细节,都是细节。

总结

在生产环境中,一台设备因系统问题无法正常生产。通过日志分析,发现Feign客户端超时导致上游微服务关闭连接,下游微服务正常执行,从而抛出"Broken pipe"错误。进一步排查发现,下游服务接口耗时过长,其中阶段S2的SQL语句更新了大量数据,导致耗时8.5秒;阶段S1重复调用了接口C 133次,总共耗时10秒。通过在SQL语句中增加条件限制和优化接口调用逻辑,问题得以解决,设备恢复正常生产。

使用的工具

  • Kibana:用于日志分析,帮助快速定位问题。
  • SkyWalking:用于监控下游微服务的性能,找出耗时的接口和SQL语句。

借鉴与启发

  • 全面分析日志:不仅要关注业务逻辑相关的日志,还要注意系统内部的异常日志,尤其是ERROR级别的日志。
  • 使用监控工具:SkyWalking等监控工具可以帮助快速定位性能瓶颈,节省排查时间。
  • 优化SQL语句:在更新数据时,确保SQL语句的条件足够精确,避免不必要的数据更新。
  • 减少接口调用:对于重复调用的接口,可以通过参数优化或缓存机制减少调用次数,提高系统性能。
  • 排查技巧 :在搜索日志时,结合trace id和日志级别(如ERROR)可以更高效地找到关键线索。

通过这些工具和方法,可以在遇到类似问题时更高效地定位和解决问题,避免生产环境中的类似故障。

推荐一个相关的课程:Java业务开发常见错误100例

在键盘与烟火之间

这一周,小学开学了,娃上一年级了,以为会鸡飞狗跳,但其实还好,甚至还可以表扬下。主要体现在以下方面:

  • 能够早起,没有迟到。
  • 早餐基本能吃饱,第一天有很多小朋友连早餐都没有吃上。
  • 放学后,作业量很少,不用催着、守着辅导作业。
  • 第二天和第三天主动领读课文,受到老师表扬。
  • 第一天他说小学不好玩,体育老师讲规矩,都把时间耗完了。第二天他说学校很好玩。
  • 大课间自己在座位上画画。
  • 引用老师的话:早读课上,两位小朋友自告奋勇,担任"领读员"。他们站姿挺拔,声音洪亮,带领着全班同学沉浸在学习氛围中,这份勇气和自信真的太棒了!

我是悟空,在键盘与烟火之间,记录生活的点点滴滴。

相关推荐
一行•坚书3 小时前
Redisson分布式锁会发生死锁问题吗?怎么发生的?
java·分布式·后端
野犬寒鸦4 小时前
力扣hot100:矩阵置零(73)(原地算法)
java·数据结构·后端·算法
fleur4 小时前
关于xxl-job的一些使用小感悟
后端
京东零售技术4 小时前
理论到实战,高可用架构踩坑说明书
后端
SimonKing4 小时前
你的图片又被别人“白嫖”了?用这篇Java防盗链攻略说再见!
java·后端·程序员
Olaf_n4 小时前
SpringBoot中的监听机制
后端
Olaf_n4 小时前
SpringBoot启动流程
后端
DS小龙哥4 小时前
基于STM32设计的智能盲人辅助导航系统设计
后端
DS小龙哥4 小时前
基于华为云设计的智能宠物喂养管理系统
后端