nginx和tomcat之间连接复用要注意的问题

一个典型的web请求处理架构是:前段nginx作为反向代理,后端使用tomcat处理具体业务。

如果没有连接复用,每个请求nginx都会和tomcat新建连接和关闭连接,这明显不是一个好的做法。所以通常我们在nginx和tomcat上配置keepalive参数。

设置这个参数后,nginx接收到tomcat的响应后一般情况不会关闭底层的socket连接,servlet在发送完响应数据后调用resp.getWriter.close()关闭输出流。到此tomcat和nginx由于设置了keepalive参数,都没有关闭socket连接,下一个请求就可以复用这个连接继续发送数据给tomcat。


连接复用减少建立连接和关闭连接所带来的网络开销,但同时也会引入一个问题:上一个请求可能还有一些数据残留在socket中,下一个请求继续使用此socket,此时tomcat解析请求行就会出错返回400错误码给nginx。


一个实际的场景:我最近在做一个上传加速模块,前端使用nginx做反向代理,后端使用tomcat服务器做业务处理。

1. nginx先向tomcat发送一个token过期的上传请求

2. tomcat接收请求并交给servlet处理,servlet发现token已过期立即返回403错误码给nginx(注意:tomcat没有读取body中的数据。问题就出在这里

3. nginx向tomcat发送另一个正常的上传请求,立即得到了400错误码。

问题就来了:为什么前一次的错误请求导致后一次的正常请求也失败了呢?

分析日志发现一个奇怪的现象:nginx访问日志和tomcat的访问日志都有相关日志,但是servlet的日志没有并且tomcat的访问日志出现一堆无意义的字符。当把nginx的keepalive关掉后,问题立刻消失。

初步猜测是连接复用的问题,通过相关同学抓包分析发现tomcat返回的403错误码后nginx继续会把没有发送完的body数据发送给tomcat,但是此时tomcat认为我已经处理完此socket连接的上一个请求了,只要有新的数据到来我就认为是一个新的请求了,此时tomcat回去尝试解析请求行,但是此时拿到的却是上一个请求的body二进制数据,tomcat解析请求行出错返回400给nginx,且打印了一条全是乱码的访问日志。


至此,我们找到了问题所以。socket复用后,tomcat在返回响应前如果没有清理本次请求的剩余垃圾数据,就会导致如上问题。最后我们的解决方案就是根据请求的content-length字段,把body中剩余数据读取出来丢掉。


另外还要注意:如果第一次请求tomcat返回400或500错误码,上述问题却不见了!那么又来一个问题:为什么403会有问题,而400或500却没问题呢?

事实上nginx会根据根据不同的错误码对socket连接进行不同处理。

403 nginx不会关闭连接

下面的错误码nginx会主动关闭连接,不管有没有设置keepalive参数

400 Bad Request
413 Request Entity Too Large
414 Request URI Too Large
497 HTTP to HTTPS
495 HTTPS Cert Error
496 HTTPS No Cert
500 Internal Server Error
501 Not Implemented

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值