【发布时间】:2015-07-22 15:42:15
【问题描述】:
我正在使用 cpp-netlib 在 C++ 中以异步模式在 Ubuntu 14.04 上开发 Web 服务。服务需要响应消息正文中通过 HTTP POST 发送的数据。我发现接收大于 1K 的输入时性能不佳,我想解决这个问题。
如果数据比较小,小于 1K,服务器几乎是立即收到数据。如果数据超过 1K,则在第一次调用异步读取回调函数后,在将第一块实际数据呈现给回调之前,会有大约一秒的延迟。在最初的延迟之后,随后的块几乎立即到达。
如何消除这种延迟?是不是用 curl 发布测试数据的神器?如何轻松测试 curl 发布数据的性能?
您可以在 github 上找到最小的 source code 演示问题。这是我用来向服务器发布数据的命令:
rcook$ curl -d @AsyncDaemon.h http://localhost:8787/foo
这是它的输出示例(带注释):
rcook$ ./async_daemon
1431387368.321863: AsyncDaemon constructor
1431387368.322446: receive thread beginning
*** It's waiting for a connection here.
1431387371.536191: begin transaction 0 on thread 24050
1431387371.536237: transaction 0 constructor
1431387371.536273: received 1206 byte request for /foo from 127.0.0.1:49402
1431387371.536312: invoked asynchronous read
1431387371.536321: end transaction handler
1431387371.536335: begin asynchronous read callback on thread 24050
1431387371.536348: read 0 bytes
1431387371.536386: invoked asynchronous read
1431387371.536394: end asynchronous read callback
*** The asynchronous read callback is invoked quickly, but gets no data.
*** There is then a pause of just over one second before the asynchronous
*** read callback is invoked again.
1431387372.537203: begin asynchronous read callback on thread 24050
1431387372.537253: read 1024 bytes
1431387372.537307: invoked asynchronous read
1431387372.537317: end asynchronous read callback
*** There is no significant delay when reading the next chunk.
1431387372.537429: begin asynchronous read callback on thread 24050
1431387372.537469: read 182 bytes
1431387372.537478: finished reading the body
1431387372.537746: wrote response
1431387372.537763: transaction 0 destructor
1431387372.537772: end asynchronous read callback
*** The server is then killed with a keyboard interrupt.
^C1431387375.382186: terminating with signal 2
1431387375.382231: initiating shutdown
1431387375.382241: stopping server
1431387375.382363: server run finished
1431387375.382423: receive thread ending
1431387375.382522: AsyncDaemon destructor
如您所见,在第一次调用异步读取回调(并接收到零字节数据,顺便说一句)后,它会请求另一块输入。此时,在输入到达之前有超过一秒的暂停,在本例中从 1431387371.536394 到 1431387372.537203。这段时间发生了什么?我怎样才能消除这种延迟?
我在网上做了一些研究,并进行了几次实验(同步与异步模式与 cpp-netlib(无效),curl 与 libcurl(无效)),但一直未能找到答案。
更新:TCP 转储
根据 jxh 的建议,我在示例事务期间运行了 tcp 转储:
00:28:01.304446 IP6 localhost.52265 > localhost.8787: Flags [S], seq 3956487146, win 43690, options [mss 65476,sackOK,TS val 395479802 ecr 0,nop,wscale 7], length 0
00:28:01.304461 IP6 localhost.8787 > localhost.52265: Flags [R.], seq 0, ack 3956487147, win 0, length 0
00:28:01.305014 IP localhost.49421 > localhost.8787: Flags [S], seq 1668603425, win 43690, options [mss 65495,sackOK,TS val 395479803 ecr 0,nop,wscale 7], length 0
00:28:01.305039 IP localhost.8787 > localhost.49421: Flags [S.], seq 4010788604, ack 1668603426, win 43690, options [mss 65495,sackOK,TS val 395479803 ecr 395479803,nop,wscale 7], length 0
00:28:01.305079 IP localhost.49421 > localhost.8787: Flags [.], ack 1, win 342, options [nop,nop,TS val 395479803 ecr 395479803], length 0
00:28:01.305185 IP localhost.49421 > localhost.8787: Flags [P.], seq 1:176, ack 1, win 342, options [nop,nop,TS val 395479803 ecr 395479803], length 175
00:28:01.305210 IP localhost.8787 > localhost.49421: Flags [.], ack 176, win 350, options [nop,nop,TS val 395479803 ecr 395479803], length 0
00:28:02.306555 IP localhost.49421 > localhost.8787: Flags [P.], seq 176:1382, ack 1, win 342, options [nop,nop,TS val 395480053 ecr 395479803], length 1206
00:28:02.306620 IP localhost.8787 > localhost.49421: Flags [.], ack 1382, win 1373, options [nop,nop,TS val 395480053 ecr 395480053], length 0
00:28:02.307223 IP localhost.8787 > localhost.49421: Flags [P.], seq 1:52, ack 1382, win 1373, options [nop,nop,TS val 395480053 ecr 395480053], length 51
00:28:02.307270 IP localhost.49421 > localhost.8787: Flags [.], ack 52, win 342, options [nop,nop,TS val 395480053 ecr 395480053], length 0
00:28:02.307494 IP localhost.8787 > localhost.49421: Flags [P.], seq 52:66, ack 1382, win 1373, options [nop,nop,TS val 395480053 ecr 395480053], length 14
00:28:02.307522 IP localhost.49421 > localhost.8787: Flags [.], ack 66, win 342, options [nop,nop,TS val 395480053 ecr 395480053], length 0
00:28:02.307765 IP localhost.8787 > localhost.49421: Flags [F.], seq 66, ack 1382, win 1373, options [nop,nop,TS val 395480053 ecr 395480053], length 0
00:28:02.307867 IP localhost.49421 > localhost.8787: Flags [F.], seq 1382, ack 67, win 342, options [nop,nop,TS val 395480053 ecr 395480053], length 0
00:28:02.307917 IP localhost.8787 > localhost.49421: Flags [.], ack 1383, win 1373, options [nop,nop,TS val 395480053 ecr 395480053], length 0
我对 tcpdump 不是很有经验,但看起来有 175 字节流向服务器(HTTP 标头?),然后延迟一秒多一点,1206 字节流向服务器,然后是 51具有最小延迟的字节块,然后是服务器响应。
这告诉我延迟是在客户端引入的,很可能是 curl。有谁知道为什么?
【问题讨论】:
-
不'read 0 bytes'表示连接已经被对端关闭了吗?
-
@MartinJames,“读取 0 字节”行仅报告传递给异步读取回调的长度参数是什么。第一次调用它时,它为零。之后,它是非零的。是的,这也让我感到惊讶。但是连接肯定没有关闭。后续读取会引入整个请求。
-
获取 TCP 转储。您是否看到服务器端拥有所有数据,但您的服务器代码只是没有将其读出?同步 I/O 是否也会显示相同的症状?
-
如果这对你没有吸引力,请尝试使用
--trace - --trace-time -
@jxh,您的建议使我发现了延迟的来源(curl 正在等待 100 Continue)解决方案(将
-H 'Expect:'添加到命令中)。非常感谢!
标签: c++ performance curl network-programming cpp-netlib