在对Apache doris http server使用SpringBoot进行重构的时候,直接使用了SpringBoot内置的web容器tomcat,当时也做了相应的测试,包括文件上传,数据导入,但是当时没有使用java http clinet API进行测试,只是使用了CURL,一切测试正常,但是随着doris 默认启用http v2(Springboot版本),社区有人反映在使用 Stream load导入数据的时候经常出现connection reset异常,
一开始出现这个异常,因为我们在curl下进行测试没有发现这个问题,虽然我们也是用stream load因为数据量小,不会引发这个异常,没有引起足够的重视,后来随着越来越多的人反映问题,我们针对性的做了测试(Java http client API各种版本),发现这个问题确实是在大文件下会引发这个问题。
后经过抓包排查,发现是tomcat对http 307协议实现有问题,抓包如下:
老版本的http服务抓包:
Http V2版本抓包:
从上面两个版本的抓包,大家可以发现,正常情况下如果使用307协议做临时重定向,PUT请求上传文件到其他服务上,当前服务收到请求后会先发送307临时重定向,然后开始传输数据,但是tomcat在发送307之前就开始传输数据了。后来去查了307协议的定义。
http 307协议定义:
HTTP 307 Temporary Redirect,临时重定向响应状态码,表示请求的资源暂时地被移动到了响应的 Location 首部所指向的 URL 上。
原始请求中的请求方法和消息主体会在重定向请求中被重用。在确实需要将重定向请求的方法转换为 GET 的场景下,可以考虑使用 303 See Other 状态码。例如,在使用 PUT 方法进行文件上传操作时,如果需要返回一条确认信息(例如“你已经成功上传了 XYZ”),而不是返回上传的资源本身,就可以使用这个状态码。
状态码 307 与 302 之间的唯一区别在于,当发送重定向请求的时候,307 状态码可以确保请求方法和消息主体不会发生变化。如果使用 302 响应状态码,一些旧客户端会错误地将请求方法转换为 GET:也就是说,在 Web 中,如果使用了 GET 以外的请求方法,且返回了 302 状态码,则重定向后的请求方法是不可预测的;但如果使用 307 状态码,之后的请求方法就是可预测的。对于 GET 请求来说,两种情况没有区别。
这个时候可以确定是我们Server端实现存在问题,后来又使用Springboot单独写了两个服务,去测试这块的逻辑,put操作发现小文件没有问题,当遇到大文件的时候还是出现,get操作没有问题,这个时候基本确定可能是tomcat的对这个协议实现是有问题的,
在网上查阅了一些资料确认是tomcat容器实现的问题,果断切换到jetty,然后测试,一切问题解决