首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >paste.httpserver和使用HTTP/1.1 Keep-alive的速度减慢;使用httperf和ab测试

paste.httpserver和使用HTTP/1.1 Keep-alive的速度减慢;使用httperf和ab测试
EN

Stack Overflow用户
提问于 2009-11-23 16:22:13
回答 1查看 3K关注 0票数 3

我有一个基于paste.httpserver的web服务器,作为HTTP和WSGI之间的适配器。当我使用httperf进行性能测量时,如果每次使用--num-conn启动一个新请求,我可以每秒处理1000多个请求。如果我使用--num-call重用连接,那么我每秒会收到大约11个请求,速度是原来的1/100。

如果我尝试ab,我会得到一个超时。

我的测试是

代码语言:javascript
复制
% ./httperf --server localhost --port 8080 --num-conn 100
...
Request rate: 1320.4 req/s (0.8 ms/req)
...

代码语言:javascript
复制
% ./httperf --server localhost --port 8080 --num-call 100
...
Request rate: 11.2 req/s (89.4 ms/req)
...

这是一个简单的可重现的服务器

代码语言:javascript
复制
from paste import httpserver

def echo_app(environ, start_response):
    n = 10000
    start_response("200 Ok", [("Content-Type", "text/plain"),
                              ("Content-Length", str(n))])
    return ["*" * n]

httpserver.serve(echo_app, protocol_version="HTTP/1.1")

它是一个多线程服务器,很难进行性能分析。下面是一个单线程的变体:

代码语言:javascript
复制
from paste import httpserver

class MyHandler(httpserver.WSGIHandler):
    sys_version = None
    server_version = "MyServer/0.0"
    protocol_version = "HTTP/1.1"

    def log_request(self, *args, **kwargs):
        pass


def echo_app(environ, start_response):
    n = 10000
    start_response("200 Ok", [("Content-Type", "text/plain"),
                              ("Content-Length", str(n))])
    return ["*" * n]

# WSGIServerBase is single-threaded
server = httpserver.WSGIServerBase(echo_app, ("localhost", 8080), MyHandler)
server.handle_request()

使用以下命令进行分析

代码语言:javascript
复制
% python2.6 -m cProfile -o paste.prof paste_slowdown.py

用它击打

代码语言:javascript
复制
%httperf --client=0/1 --server=localhost --port=8080 --uri=/ \ 
   --send-buffer=4096 --recv-buffer=16384 --num-conns=1 --num-calls=500

我得到的个人资料如下

代码语言:javascript
复制
>>> p=pstats.Stats("paste.prof")
>>> p.strip_dirs().sort_stats("cumulative").print_stats()
Sun Nov 22 21:31:57 2009    paste.prof

         109749 function calls in 46.570 CPU seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   46.571   46.571 {execfile}
        1    0.001    0.001   46.570   46.570 paste_slowdown.py:2(<module>)
        1    0.000    0.000   46.115   46.115 SocketServer.py:250(handle_request)
        1    0.000    0.000   44.675   44.675 SocketServer.py:268(_handle_request_noblock)
        1    0.000    0.000   44.675   44.675 SocketServer.py:301(process_request)
        1    0.000    0.000   44.675   44.675 SocketServer.py:318(finish_request)
        1    0.000    0.000   44.675   44.675 SocketServer.py:609(__init__)
        1    0.000    0.000   44.675   44.675 httpserver.py:456(handle)
        1    0.001    0.001   44.675   44.675 BaseHTTPServer.py:325(handle)
      501    0.006    0.000   44.674    0.089 httpserver.py:440(handle_one_request)
     2001    0.020    0.000   44.383    0.022 socket.py:373(readline)
      501   44.354    0.089   44.354    0.089 {method 'recv' of '_socket.socket' objects}
        1    1.440    1.440    1.440    1.440 {select.select}
         ....

您可以看到,几乎所有的时间都在recv中。

我决定放弃httpref,编写自己的HTTP/1.1-with-keep-alive请求,并使用netcat发送:

代码语言:javascript
复制
GET / HTTP/1.1
Location: localhost
Connection: Keep-Alive
Content-Length: 0

GET / HTTP/1.1
Location: localhost
Connection: Keep-Alive
Content-Length: 0

 ... repeat 97 more times, to have 99 keep-alives in total ...

GET / HTTP/1.1
Location: localhost
Connection: Close
Content-Length: 0

和我一起发送的

代码语言:javascript
复制
nc localhost 8080 < ~/src/send_to_paste.txt

100个请求的总时间是0.03秒,所以它的性能非常好。

这表明httperf做错了什么(但它是一段广泛使用和受人尊敬的代码),所以我尝试使用'ab‘

代码语言:javascript
复制
% ab -n 100 -k localhost:8080/
This is ApacheBench, Version 1.3d <$Revision: 1.73 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)...
Server timed out

: Operation now in progress

在检测服务器时,它处理一个请求,并等待第二个请求。

知道是怎么回事吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2009-11-25 16:00:10

经过一些努力,这似乎是Nagle's algorithm或延迟确认,或他们之间的交互。如果我做像这样的事情,它就会消失

代码语言:javascript
复制
server.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

我是怎么找到它的?首先,我检测了socket.py中的每个' recv‘,这样我就可以知道哪个recv正在等待。我会看到11个recv中有5个延迟了近200ms。我搞不懂为什么会有任何延误。然后我使用Wireshark查看消息,并注意到实际上是从服务器到客户端的发送有延迟。这意味着来自我的客户端的传出消息中的TCP层中的某些东西。

一位朋友提出了一个显而易见的建议,我搜索了"200ms套接字延迟“,找到了对这个问题的描述。

粘贴跟踪报告位于http://trac.pythonpaste.org/pythonpaste/ticket/392以及一个补丁程序,该补丁程序在处理程序使用HTTP/1.1时启用TCP_NODELAY。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1781766

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档