質問

私は、HTTPおよびWSGI間adapaterとしてpaste.httpserverに基づいてWebサーバーを持っています。私はhttperfで性能測定を行うと、私は--num-CONNを使用して新しい要求を毎回起動した場合、私は毎秒1,000を超える要求を行うことができます。私が代わりに--numコールを使用して接続を再利用する場合、私は、毎秒11件の要求、速さの1/100分の約入手ます。

私はAB Iをしようとした場合、タイムアウトを取得します。

私のテストです。

% ./httperf --server localhost --port 8080 --num-conn 100
...
Request rate: 1320.4 req/s (0.8 ms/req)
...

% ./httperf --server localhost --port 8080 --num-call 100
...
Request rate: 11.2 req/s (89.4 ms/req)
...

ここでのシンプルな再現性のあるサーバー

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")

これは、プロファイルへのハードである、マルチスレッドサーバーです。ここではシングルスレッドでばらつきがあります:

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()

タグであることプロファイリング
% python2.6 -m cProfile -o paste.prof paste_slowdown.py

でそれを打ちます
%httperf --client=0/1 --server=localhost --port=8080 --uri=/ \ 
   --send-buffer=4096 --recv-buffer=16384 --num-conns=1 --num-calls=500

私は

のようなプロファイルを取得します
>>> 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-と-キープアライブ要求を書いて、netcatをを使用してそれを送信することを決定しました

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
私が送信され、

nc localhost 8080 < ~/src/send_to_paste.txt

それは非常に良好なパフォーマンスですので、100の要求のための合計時間は、0.03秒であった。

これはhttperfは何か間違ってやっていることを示唆している(それはだ広く使用され、コードの一部を尊敬)私は「AB」を試してみましたので、

% 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

サーバーのインスツルメント、それは一つのリクエストを処理し、秒を待っています。

何が起こっているの任意のアイデア?

役に立ちましたか?

解決

いくつかの努力の後、それはどちらか Nagleアルゴリズムにまたは遅延ACKのようです、またはそれらの間の相互作用。それは離れて行く私のような何かをする場合は、

server.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

どのように私はそれを追跡しましたか?私は待っていたのrecvを見つけ出すことができるようにまず、私は、socket.py内のすべての「RECV」をインストルメント。私は11の約5 RECVのうち、ほとんどは200msの遅延を持っていた見ること。任意の遅延があった私はなぜ把握できませんでした。私はその後、メッセージを監視するためにWiresharkのを使用し、それが実際に遅延していたサーバーからクライアントへ送信したことに気づきました。私のクライアントから送信メッセージにおけるTCP層であることを意味何かます。

友人は明白なことを示唆し、そして私は「200msの遅延ソケット」を検索し、この問題の記述を見つけます。

ペーストTracのレポートでは、 http://trac.pythonpaste.org/pythonpaste/ticket/であります392ハンドラがHTTP / 1.1を使用するときTCP_NODELAYを可能にするパッチと共に

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top