Golang的(* http.ResponseWriter)Write()方法是否会阻塞,直到客户端接收到数据?

问题描述 投票:-3回答:1

我问这个问题,是因为我有一个非常奇怪的令人困惑的经历,即将讲给我听。

我正在对HTTP API服务器进行检测,以观察服务器和客户端之间存在延迟的情况。我有一个设置,其中包含一台服务器和十二个与10Gbps以太网结构连接的客户端。我测量了在5种情况下满足某些API请求所需的时间。在每种情况下,我都将服务器与客户端之间的延迟设置为以下值之一:使用tc-netem(8)实用程序将无延迟(我称为基准),25ms,50ms,250ms或400ms。

因为我使用直方图存储区来量化服务时间,所以我发现无论发生什么情况,所有请求都在不到50ms的时间内处理,这显然没有任何意义,例如在400ms的情况下,至少应为400毫秒左右(因为我只是在测量从请求到达服务器到HTTP Write()函数返回的持续时间)。请注意,响应对象的大小在1Kb到10Kb之间。

[最初,我怀疑*http.ResponsWriterWrite()函数是异步的,并且在客户端接收到数据之前立即返回。因此,我决定通过编写一个玩具HTTP服务器来检验该假设,该服务器为使用dd(1)/dev/urandom生成的文件的内容提供服务,以便能够重新配置响应大小。这是服务器:

var response []byte

func httpHandler(w http.ResponseWriter, r * http.Request) {

    switch r.Method {
        case "GET":
            now: = time.Now()
            w.Write(response)
            elapsed: = time.Since(now)
            mcs: = float64(elapsed / time.Microsecond)
            s: = elapsed.Seconds()
            log.Printf("Elapsed time in mcs: %v, sec:%v", mcs, s)
    }
}

func main() {
    response, _ = ioutil.ReadFile("BigFile")

    http.HandleFunc("/hd", httpHandler)
    http.ListenAndServe(":8089", nil)
}

然后我像这样启动服务器:dd if=/dev/urandom of=BigFile bs=$VARIABLE_SIZE count=1 && ./server

从客户端发出time curl -X GET $SERVER_IP:8089/hd --output /dev/null

我尝试在服务器和每个客户端之间使用400ms的模拟延迟,使用范围为[1Kb,500Mb]的许多$ VARIABLE_SIZE值。长话短说,我注意到Write()方法阻塞,直到当响应大小足够大到可以从视觉上注意到(数十兆字节)时发送数据为止。但是,当响应大小较小时,与客户端报告的值相比,服务器不会报告精神上合理的服务时间。对于10Kb的文件,客户端报告1.6秒,而服务器报告67微秒(这根本没有意义,即使我是人类,我也注意到客户端报告的时间稍有延迟) 。

为了更进一步,我尝试找出服务器从哪个响应大小开始返回可接受的时间。经过使用二进制搜索算法的多次试验后,我发现服务器对于小于86501字节大小的响应总是返回几微秒[20us,600us],并且对于大于等于86501字节的请求(通常是)返回期望的(可接受的)时间客户报告的时间的一半)。例如,对于86501字节的响应,客户端报告了4秒,而服务器报告了365微秒。对于86502字节,客户端报告为4s,服务器报告为1.6s。我多次使用不同的服务器重复了这一经验,其行为始终是相同的。数字86502看起来像魔术!

此经历解释了我最初的怪异发现,因为所有API响应的大小都小于10Kb。但是,这为一个严重的问题打开了大门。地球上到底发生了什么,以及如何解释这种行为?

我尝试搜索答案,但没有找到任何答案。我唯一可以考虑的事情可能与Linux的套接字大小以及Go是否以非阻塞方式进行系统调用有关。但是,在发送方(服务器)可以返回之前,接收方(客户端)应确认传输TCP响应的AFAIK,所有HTTP数据包!打破这种假设(在这种情况下看起来)可能会导致灾难!有人可以提供这种奇怪行为的解释吗?

技术细节:

Go version: 12
OS: Debian Buster
Arch: x86_64

我问这个问题是因为我有一个非常奇怪的令人困惑的经历,我将要讲述。我正在对HTTP API服务器进行检测,以观察在...

http go networking server instrumentation
1个回答
2
投票

我推测问题实际上是用一种奇怪的方式提出的:您似乎正在猜测HTTP的工作原理,而不是查看整个堆栈。

© www.soinside.com 2019 - 2024. All rights reserved.