在实际业务中遇到了一个很奇怪的问题,服务 A 通过 HTTP 请求访问 Go 语言的服务 B ,少部分请求会超时。进一步分析发现,如果一个请求超时,其重试也一定会超时,说明针对特定请求内容,超时是必然发生的问题。通过检查服务 B 的处理日志发现,对于超时的请求,其业务逻辑处理的耗时正常。
一开始通过排除法来分析,逐步替换怀疑有问题的模块,结果并没有定位到问题。后来通过抓包,分析正常包与超时包的区别,合理猜测有问题的部分并进行验证,最终定位到原来是 Expect: 100-continue 这个请求 HTTP header 导致了这里的超时。整个排查和修复过程,踩了不少坑,记录下来可以给大家参考。
完整内容在: 由 HTTP Header 引起的请求超时问题排查
HTTP 协议中当客户端要发送一个包含大量数据的请求时(通常是 POST 或 PUT 请求),如果服务器无法处理这个请求(例如因为请求的数据格式不正确或者没有权限),那么客户端会浪费大量的资源来发送这些数据。为了解决这个问题,HTTP/1.1 引入了 Expect: 100-continue 头部,允许客户端在发送请求体前询问服务器是否愿意接收请求。如果服务器不能处理请求,客户端就可以不发送大量数据,从而节省资源。
这里具体的实现原理是把一个完整的 HTTP 请求分成两个阶段来发送。第一个阶段只发送 HTTP 请求的头部,第二个阶段在收到服务器确认后才发送 HTTP 请求的主体。从 HTTP 的角度看,仍然是一个单一的 HTTP 请求,只是改变了请求的发送方式。
这里一般靠网络库和底层的 TCP 协议来实现,当使用了”Expect: 100-continue”头部,网络库(比如 libcurl)会先只发送 Expect 部分的 TCP 数据,然后等待服务器的 100 Continue 响应。收到 TCP 回复后,网络库会接着发送请求主体的 TCP 数据包。如果服务器没有返回 100 Continue 响应,网络库可能会选择等待一段时间,然后发送请求主体,或者关闭连接。
1
lasuar 2023-08-09 08:50:04 +08:00
课上了,该说说为何服务器没有即时响应 100 Continue ?这到底属于服务端接口问题。
|
2
crystom 2023-08-09 09:06:46 +08:00 1
这个过时了,客户端不建议添加
|
3
zhangkunkyle 2023-08-09 09:07:30 +08:00
学到了
|
4
dode 2023-08-09 09:08:10 +08:00
后端把这个请求头逻辑写死处理,
|
5
runliuv 2023-08-09 09:24:55 +08:00
Expect: 100-continue , 一般设置为 false.
|
6
flycat1626 2023-08-09 09:26:59 +08:00
内容都写到这份上了,还非要导流自己的 blog 吗?真想交流的话,格局还是不够大啊。
|
7
lsk569937453 2023-08-09 09:31:54 +08:00
看样子不用这个 c++库的一般不会碰到。
|
8
zzzkkk 2023-08-09 09:34:05 +08:00
所以你的 A 服务用来什么 http client
不要发 expect 100-continue 不就好了 |
9
vfs 2023-08-09 09:34:33 +08:00
这娃所有的文章看起来都是给博客导流的。。。
|
12
xuelang OP 导流有啥问题吗?
|
13
xuelang OP @lsk569937453 嗯,试了 go 的库,没有自动加这个 header
|
15
xuelang OP |
16
xuhai951753 2023-08-09 10:27:42 +08:00
我在想这种情况下是不是超时是正确的,因为服务器没处理,不然可能会过载
当然服务器因为 bug 没处理那是另外一回事 |
17
xuelang OP @xuhai951753 这种服务 mesh 层没处理好 http 的转发,和过载没关系的
|