CherryPy在8个请求线程下基准测试速度比7个慢60倍

3 投票
1 回答
2104 浏览
提问于 2025-04-16 11:48

我很好奇,为什么在用ab测试Python的CherryPy网络服务器时,当我设置为-c 7(7个并发线程)时,它能处理1500个请求每秒(这大约是我预期的),但当我改成-c 8时,速度一下子降到每秒25个请求。我是在一台64位的Windows机器上运行CherryPy,设置了numthreads=10(但无论我用numthreads=8还是20都没有区别),这台机器有四个核心,运行的是Python 2.6。

我有点怀疑Python的全局解释器锁(GIL)可能是问题的一部分,但我不明白为什么只有在并发请求线程达到8时才会出现这种情况。在一台四核的机器上,我本以为在-c 4时就会有变化,但事实并不是这样。

我使用的是随web.py一起提供的单文件CherryPy网络服务器,下面是我正在测试的WSGI应用:

from web.wsgiserver import CherryPyWSGIServer

def application(environ, start_response):
    start_response("200 OK", [("Content-type", "text/plain")])
    return ["Hello World!",]

server = CherryPyWSGIServer(('0.0.0.0', 80), application, numthreads=10)
try:
    server.start()
except KeyboardInterrupt:
    server.stop()

对于7个和8个并发线程,ab的输出结果是:

C:\\> ab -n 1000 -c 7 http://localhost/
...
Concurrency Level:      7
Time taken for tests:   0.670 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      130000 bytes
HTML transferred:       12000 bytes
Requests per second:    1492.39 [#/sec] (mean)
Time per request:       4.690 [ms] (mean)
Time per request:       0.670 [ms] (mean, across all concurrent requests)
Transfer rate:          189.46 [Kbytes/sec] received

C:\\> ab -n 1000 -c 8 http://localhost/
...
Concurrency Level:      8
Time taken for tests:   7.169 seconds
Complete requests:      158
Failed requests:        0
Write errors:           0
Total transferred:      20540 bytes
HTML transferred:       1896 bytes
Requests per second:    22.04 [#/sec] (mean)
Time per request:       362.973 [ms] (mean)
Time per request:       45.372 [ms] (mean, across all concurrent requests)
Transfer rate:          2.80 [Kbytes/sec] received

1 个回答

3

在我的Linux电脑上,出现了TCP数据包的重传问题,主要是因为ab的原因,不过我也不太确定具体是什么情况:

No.     Time        Source                Destination           Protocol Info                                                            Delta
  10682 21.218156   127.0.0.1             127.0.0.1             TCP      http-alt > 57246 [SYN, ACK] Seq=0 Ack=0 Win=32768 Len=0 MSS=16396 TSV=17307504 TSER=17306704 WS=6 21.218156
  10683 21.218205   127.0.0.1             127.0.0.1             TCP      57246 > http-alt [ACK] Seq=82 Ack=1 Win=513 Len=0 TSV=17307504 TSER=17307504 SLE=0 SRE=1 0.000049
  10701 29.306438   127.0.0.1             127.0.0.1             HTTP     [TCP Retransmission] GET / HTTP/1.0                             8.088233
  10703 29.306536   127.0.0.1             127.0.0.1             TCP      http-alt > 57246 [ACK] Seq=1 Ack=82 Win=512 Len=0 TSV=17309526 TSER=17309526 0.000098
  10704 29.308555   127.0.0.1             127.0.0.1             TCP      [TCP segment of a reassembled PDU]                              0.002019
  10705 29.308628   127.0.0.1             127.0.0.1             TCP      57246 > http-alt [ACK] Seq=82 Ack=107 Win=513 Len=0 TSV=17309526 TSER=17309526 0.000073
  10707 29.309718   127.0.0.1             127.0.0.1             TCP      [TCP segment of a reassembled PDU]                              0.001090
  10708 29.309754   127.0.0.1             127.0.0.1             TCP      57246 > http-alt [ACK] Seq=82 Ack=119 Win=513 Len=0 TSV=17309526 TSER=17309526 0.000036
  10710 29.309992   127.0.0.1             127.0.0.1             HTTP     HTTP/1.1 200 OK  (text/plain)                                   0.000238
  10711 29.310572   127.0.0.1             127.0.0.1             TCP      57246 > http-alt [FIN, ACK] Seq=82 Ack=120 Win=513 Len=0 TSV=17309527 TSER=17309526 0.000580
  10712 29.310661   127.0.0.1             127.0.0.1             TCP      http-alt > 57246 [ACK] Seq=120 Ack=83 Win=512 Len=0 TSV=17309527 TSER=17309527 0.000089

原始的“GET”请求数据包在Wireshark中也没有被捕捉到。出于某种原因,ab尝试发送请求但失败了,尽管TCP连接的确认(ACK)是正常的。然后,客户端的TCP协议栈会等几秒钟,期待一个从未发送的数据包的确认,结果没有收到确认后,它就重试了一次,最后成功了。

就我个人而言,我觉得没必要太担心。如果真有问题,那也不是CherryPy的错。可能是ab内部的原因,使用的是HTTP/1.0而不是1.1,缺少保持连接的设置,使用的是localhost而不是实际的网络连接(这会模拟网络流量的某些情况,但忽略其他情况),或者是使用Windows系统(眨眼),同一接口上的其他流量,CPU的负载……问题的原因可以说是五花八门。

撰写回答