Nginx频繁报状态码400错误,定位到原因是丢包引起

目录 

一、背景说明

二、访问日志分析

三、TCP抓包分析

四、结论


一、背景说明

最近线上服务发布,完成后一切平静,到下午用户量正常起来后,开始频繁收到Nginx状态码是400的告警,初步确认是偶尔出现,还好还好!

400通常理解为客户端请求错误,一般原因是请求数据中有不合法字符,请求头缺失host头。但这次案例另有原因。详细回顾下定位过程和方法,供大家参考。

二、访问日志分析

服务器的负载均衡LB中状态码正常的日志:

Nginx频繁报状态码400错误,定位到原因是丢包引起_第1张图片

LB侧状态码是400的日志:

Nginx频繁报状态码400错误,定位到原因是丢包引起_第2张图片 对比发现一个很明显的规律:request_length在400状态码时偏低,upstream_response_time普遍到4s。

看到这个不得不有一个大胆的怀疑是由于Nginx未收到完整请求数据,而标记请求为400。

三、TCP抓包分析

接下来可能需要进行TCP抓包分析看看有没有线索。

到Nginx所在机器,通过tcpdump抓包

sudo  tcpdump -A -i et11 -w tcpdump.data port 1000

et11是网卡名称,1000是nginx接收请求的监听端口,tcpdump.data是包数据保存文件。

利用wireshark进行抓包分析,以其中一条请求400的日志时间结合请求耗时,倒推出该次请求大概的发生时间点。

 图中是一条400的访问日志,推算发生时间大概是在(38分31秒减去4.98秒)38分26秒。

先看一个正常的请求的TCP包序列:

 客户端端口50469与服务器建立连接的通讯过程:

550-552是连接建立的三次握手,553-560完成了一次完整的请求(557忽略),发送请求时,有一个553的分包PDU(TCP segment of a eassembled PDU),555是请求包,559是响应包,状态码是200。

再来定为400时的TCP包序列,补充一点定位到这个请求包的方式是通过包的到达时间,wireshark显示示意如下:

Nginx频繁报状态码400错误,定位到原因是丢包引起_第3张图片

该条请求的包序列如下: 


 2434-2436是建立连接的三次握手,后续接收到的请求包数据只有2437和一个响应客户端的ACK,这就说明,服务器只收到一个请求分包,后续就没再接收到,大概等待5s左右,收到一个RST断开连接的包,此时Nginx就会在日志中记录一条400状态码的请求。

四、结论

至此原因基本定位到是丢包导致,单纯从服务侧很难再继续追踪,后续希望从客户端侧能进一步排查丢包原因,客户端的请求方式是否需要优化。

后续:经客户端确认可能与设置超时时间过短有关,客户端在大并发发送后台请求时,超时又比较短,会存在大量中断请求的情况。

你可能感兴趣的:(Linux,服务器,运维,抓包,TCP,400错误)