后端接口请求经过:android->nginx->tomcat(gateway)->tomcat(业务service)。
问题发生的场景:android循环请求业务的一个添加接口,第一百次时(绝大多数情况是100,偶尔也有小于100的时候,稳定复现)service的tomcat返回OK,gateway把响应转个nginx,nginx没有正确响应。nginx配置了http1.1,后端两个tomcat版本是9.0.60.抓包看的直观原因是service前99个响应的响应头Connection: keep-alive,最后一个是Connection: close.
service端口的抓包
第100个请求gateway把响应转个nginx,nginx会报错:upstream sent invalid chunked response while reading upstream, client: XXXX, server: localhost, request: "POST /api/XXX HTTP/1.1", upstream: "http://XXX:XXX/api/XXX".百度看这种错误都是nginx需要配置http1.1,但是已经配置了。
同时在gateway端口的抓包
其他相关:
1.nginx的配置比较简单
upstream app {
server XXXX:8105;
#keepalive 200;
}
server {
listen XXX;
server_name localhost;
#keepalive_requests 10000;
location / {
proxy_pass http://app;
client_max_body_size 2048m;
#proxy_buffer_size 128k;
#proxy_buffers 32 32k;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2.关于service为什么第100个请求响应头给了Connection: close,可能和tomcat的参数server.tomcat.max-keep-alive-requests有关,但是改了这个值现象也没有改变。所有想搞明白为啥在这种情况下nginx抓包中直接就挥手了没有正确处理。在wireshark中,追踪tcp流可以看到gateway的响应,但是追踪http流就只有请求。
==========================2023-06-24补充=======================
1.抓包不是同一时间抓的
2.gateway不是用的现有框架,是用的RestTemplate做的转发,代码如下
public ResponseEntity String redirectNonFile(HttpServletRequest request, String routeUrl, String prefix)
throws Exception
{
// build up the redirect URL
String redirectUrl = createRedirectUrl(request, routeUrl, prefix);
log.info("redirectUrl={}", redirectUrl);
RequestEntity requestEntity = createRequestEntity(request, redirectUrl);
return restTemplate.exchange(requestEntity, String.class);
}
3.第100个请求TCP层service给gateway的响应和gateway给nginx的响应是存在差异的(也不是同一时间的抓包,但是现象是相同的)
service给gateway的响应
gateway给nginx的响应
缺少了"21.."和结尾的"..",两个".."对应的是0d0a表示"\r\n",21不明白是什么意思,这个是百度ssseerr999童鞋回答中Transfer-Encoding: chunked学到的。"\r\n"是数据块的结尾,这么看nginx的处理没有问题。问题就变成了RestTemplate在接收到响应头Connection:close和Transfer-Encoding: chunked时转发的响应少了一部分数据。
==================2023-06-29问题解决===================
前段时间用server.tomcat.max-keep-alive-requests=10000减少了出现的次数。确认是网关测的问题后,做了如下修改解决。
本来是小问题,饶了一大圈...
虽然不清楚这个问题的正确答案,但是我看截图上有个奇怪的点。
看了wireshark的截图,tomcat发送了PSH ACK后,nginx返回了ACK,这个ACK是收到了消息,再返回的FIN+ACK开始断开连接的,所以这里应该是没问题的。
至于为什么nginx在接收到了响应后,还是给客户端返回了空的响应,按照日志的记录,应该是上游的响应有问题。但是实际看上去好像也没啥问题。
最后虽然不知道问题的原因,我感觉可以试试让上游不要返回Transfer-Encoding: chunked,说不定可以解决这个问题。