设为首页 加入收藏

TOP

Nginx神奇的499竟然不在HTTP响应码标准内?快来了解一下!(二)
2023-09-23 15:44:30 】 浏览:122
Tags:Nginx 499 HTTP 应码标 解一下
9官方定义,这种行为被Nginx判定499状态:

  • 对内表现为记录499日志
  • 对外表现为回复HTTP 400给消息网关

所以,在服务端的Nginx大量499日志条目;在消息网关那头,如果它也做Web日志,就是400报错。

5 从现象到本质

为什么客户端先发送FIN,然后才发送POST body?

回到Wireshark窗口,再关注6号报文:

离上个报文相差了2s。

往前看4号报文:

离3号报文相差3s。加起来,6号报文离TCP握手完成,正好隔 5s整

一般出现这种整数,就越可疑,因为如果是系统或网络错乱导致,时间分布应 随机,不可能卡在整数时间。经验看, 这和人为设置有关。于是客户仔细查看微信网关使用文档,发现5s超时设置。即若一个HTTP事务无法在5s内完成,就关闭这连接。

啥叫无法完成?

在这抓包里即:HTTP header报文发过去了,但HTTP body报文没一起过去(网络原因导致)。而由于初始阶段报文少, 无法凑齐3个DupAck,所以快速重传没有启动,只好依赖超时重传(12 讲),且这多次超时重传也失败,服务端只好持续等待这丢失的报文。5s后,客户端没收到服务端响应,就主动关闭这次连接(可以下次再试,这次就不继续干等)。

即该场景里Nginx 499错误日志主因:

  • 消息网关—>服务器 方向上的一个TCP包丢失(案例里是HTTP POST body报文),引起服务端空闲等待
  • 消息网关有5s超时设置,即连接达到5s,消息网关就发FIN关闭连接

逻辑链:

  • 要解决499报错的问题,就需要解决5s超时
  • 要解决5s超时,就要解决丢包
  • 要解决丢包,就要改善网络链路质量

最根本解决方案,如何确保客户端到服务端的 网络连接 可靠稳定,使类似的报文延迟现象降到最低。只要不丢包不延迟,HTTP事务就能在5s内完成,消息网关就不会启动5s超时断开连接机制。

跟客户还有网关工程师配合,确实发现网关到公有云的一条链路有问题。更换为另外一条链路后,丢包率大幅降低,问题极大改善。虽然还是有极小比例的错误日志(约万分之一),但对客户已在可接受范围。

因为丢包,客户端FIN报文跟HTTP POST body报文一样,也可能丢失。不过,无论这FIN是否被服务端及时收到,这次HTTP事务本身也已在客户端记为失败。

链路丢包这种问题挺明显,为啥没及时发现?

  • 虽然对主要链路的整体状况有细致的监控,但这里的网关到客户的公有云服务属于“点到点”的链接,本身也属于客户自身的业务,公有云难以对这种情况做监控,理想情况是客户自己来实现监控。
  • 客户的消息量很大,哪怕整体失败比例不高,但乘以绝对的消息量,产生的错误的绝对数也就比较可观了。

至于Nginx为何“创造”499状态码, Nginx源码 注释写得清楚。并非标新立异,而确实是为了弥补标准HTTP协议不足:

/*
 * HTTP does not define the code for the case when a client closed
 * the connection while we are processing its request so we introduce
 * own code to log such situation when a client has closed the connection
 * before we even try to send the HTTP header to it
 */
#define NGX_HTTP_CLIENT_CLOSED_REQUEST     499

6 总结

Nginx 499是Nginx定义状态码,不是RFC中定义HTTP状态码。表示“Nginx收到完整的HTTP request前(或者已经接收到完整的request但还没来得及发送HTTP response前),客户端试图关闭TCP连接”这种反常情况。

超时时间跟499报错数量也有直接关系。如果我们有办法延长消息网关的超时时间,比如从5秒改为50秒,那么客户端就有比较充足的时间去等待丢失的报文被成功重传,从而在50秒内完成HTTP事务,499日志也会少很多。

关注网络延迟对通信的影响。比如客户端发出的两个报文(报文3和报文4)间隔了3秒钟,这在网络通信中是个非常大的延迟。而造成这么大延迟的原因,会有两种可能:

  • 消息网关端本身是在握手后隔了3秒才发送了这个报文,属 应用层问题
  • 消息网关在握手后立刻发送了这个报文,但在公网上丢失了,微信消息网关就根据“超时重传”的机制重新发了这个报文,并于3秒后到达。属 网络链路问题

由于上面的抓包是在服务端做的,所以未到达服务器的包自然也不可能抓到,也就是无法确定是具体哪一种原因(客户端应用层问题或网络链路问题)导致,但这并不影响结论。

公网丢包现象不可能完全消失。千分之一左右公网丢包率是正常范围。由于:

  • 客户发送量较大(主因)
  • 微信消息网关设置5s超时相对较短(次要原因)

问题就会在这个案例中被集中暴露。

设置更长超时阈值(如50s)能解决?出错率会降低不少,但新问题:

  • 消息网关会有更多的资源消耗(内存、TCP源端口、计算能力等)
  • 消息网关处理事务的平均耗时会增加

所以,5s是权衡后的合适方案。

排查的方法论,对更广泛的应用层报错日志的排查,推荐:

  • 先查应用文档,初步确定问题性质,大体确定排查方向

  • 对比应用日志和抓取的报文,在传输层和网络层寻找可疑报文。这步,可采用比对策略找到可疑报文:

    • 日志中的IP跟报文中的IP对应
    • 日志和报文的时间戳对应
    • 应用层请求信息和报文信息对应
  • 结合协议规范和报文现象,推导出根因

FAQ

  • 第7个报文是DupAck,为什么没触发快速重传?
  • 消息网关那头的应用日志应该不是499,那会是啥样日志?

本文由博客一文多发平台 OpenWrite 发布!

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java有关队列的基本操作 下一篇Spring Cloud 轻松解决跨域,别再..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目