8

異常な問題が発生しています。C++ Boost.ASIO Web サーバーがあり、着信要求を処理するために次のコードを使用しています。

boost::asio::async_read_until(
    socket_,
    response_,
    "\r\n\r\n",
    boost::bind(
            &connection::handle_read_headers,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
    )
);

(「socket_」はブースト::asio::ip::tcp::socket、「response_」はブースト::asio::streambuf)

私はリクエストのヘッダーを取得しようとしていますが、後でリクエストヘッダーから解析された「Content-Length」と一致する transfer_exactly を使用して 2 番目の async_read_until を実行します。問題は、上記のコードが非常に最新のサーバーに戻るのに 100 ~ 900 ミリ秒かかっていることです (その読み取りブロックから、handle_read_headers() が呼び出されるまで)。着信要求は次のようになります。

POST /load HTTP/1.1
host: www.mysite.com
Accept: */*
Accept-Encoding: gzip,deflate
Content-type: application/x-www-form-urlencoded
From: googlebot(at)googlebot.com
Origin: http://www.mysite.com
Referer: http://www.mysite.com/another-page/
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
X-Forwarded-For: 66.249.75.103
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Content-Length: 287
Connection: keep-alive

and-the-actual-content-is-here.... (287 bytes worth)

ヘッダーは \r\n\r\n で終了しているように見え、EOF まで読み取る前に handle_read_headers() 関数をトリガーします (ページ全体を読み取らないため) - 実際には正規表現をトリップしています。そして、これらのリクエストは Google から来ているので、遅れているわけではないと確信しています。

戻るのに時間がかかる理由について見落としているものはありますか? 私が見逃したかもしれない aync_read_until の他のキャッチはありますか?

ありがとう!

編集/更新: さて、私は非常に混乱しています。メガバイトの提案を試す際に、streambuf から文字配列に切り替えて (うまくいきませんでした)、コードをリファクタリングして async_read_until ではなく async_read_some を使用し、区切り記号を手動でスキャンしました。また、すべての OS 変数 (sysctrl.conf) をボーン ストックのデフォルトにリセットしました (可能性を絞り込むため)。残念ながら、次のコードでは、同じ受信 POST リクエストで handle_read() を呼び出しているため、まだ 100 ~ 900 ミリ秒の遅延が見られます。

socket_.async_read_some(
    boost::asio::buffer(response_),
    boost::bind(
        &connection::handle_read,
        shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred
    )
);

ここで、response_ は次のようになります。

boost::array<char, 4096> response_;

役に立たない(同じ100〜900ミリ秒の遅延)。これが正常であるはずがありません - 何か考えはありますか?

EDIT2:Rhashimoto の推奨に従って、ハンドラーの追跡を有効にすると、ログに次の奇妙な点が見つかりました。

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed

async_accept と async_receive の間には 700 ミリ秒以上あります。コードでは、このブロックから (事実上、 http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.htmlの「HTTP Server 2」から直接) - server. cpp および connection.cpp):

new_connection_->start();
new_connection_.reset(new connection(
        io_service_pool_.get_io_service()
));
acceptor_.async_accept(
        new_connection_->socket(),
        boost::bind(
                &server::handle_accept,
                this,
                boost::asio::placeholders::error
        )
);

そして start() から:

void connection::start()
{
    boost::asio::async_read_until(
        socket_,
        response_,
        "\r\n\r\n",
        boost::bind(
            &connection::handle_read_headers,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
        )
    );
}

そして、handle_read_headers() が呼び出されると、700ms が経過します。

誰かアイデアはありますか?私は完全に迷っています。

本当にありがとう!

4

1 に答える 1

4

ハンドラーのログを見てみましょう

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed

ログから、2 回呼び出されていることがわかりますasync_receive。最初の呼び出し (#508) は、ハンドラーのセットアップ (#506) の 734 ミリ秒後です。ここで、async_receiveハンドラーのセットアップ (#508) の 53 マイクロ秒後に秒が呼び出されます (#510)。以上で、データ (404 バイト) が TCP スタックで既に準備ができているため、2 番目のハンドラー呼び出しが非常に高速に開始されました。

結論: これはハンドラー呼び出しの遅延ではなく、トランスポートの遅延です。おそらく ISP やバランサーに問題があるか、Google がリクエストや遅延の設定であなたを煩わせたくないのでしょう。

UPD:これを確認できると思いますtcpdump

io_service_pool_PS HTTPサーバー2の例からの実装は好きではありません。これもいくつかの問題を引き起こす可能性がありますが、現在のケースではないと思います。

于 2013-07-07T14:26:50.930 に答える