2013-07-04 2 views
8

이상한 문제가 있습니다. 나는 C++ Boost.ASIO 웹 서버를 가지고 있고,이 코드를 사용하고 들어오는 요청을 처리하기 위해 :C++ Boost.ASIO async_read_until slow

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 : 소켓입니다 및 "response_"은 boost :: asio :: streambuf입니다.

나는 요청의 헤더를 잡으려고하고 있습니다. 그리고 나서 나중에 transfer_exactly가 구문 분석 된 "Content-Length"와 일치하는 두 번째 async_read_until을 수행합니다. 요청 헤더. 문제는 위의 코드가 매우 현대적인 서버 (handle_read_headers()가 호출 될 때까지 읽기 블록에서 반환)에 100-900ms가 걸리는 것입니다.

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을 가진 다른 catch는 내가 놓친 것일 수 있습니까?

감사합니다.

편집/업데이트 : 좋아, 이제 나는 매우 혼란스러워. 메가 바이트의 제안을 시도하면서, 나는 streambuf에서 문자 배열로 전환했다. 그런 다음 async_read_until 대신 async_read_some을 사용하도록 코드를 리팩토링하고, 수동으로 구분 된 문자를 스캔했다. 또한 OS 변수 (sysctrl.conf)를 모든 기본 변수로 재설정하여 가능성을 줄였습니다. response_ 지금

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

입니다 : 불행하게도, 난 여전히 같은 들어오는 POST 요청과) (handle_read를 호출 다음 코드 100-900ms 지연을보고 있어요 아무 소용이

boost::array<char, 4096> response_; 

(동일 100-900ms 지연). 이것이 정상적인 방법은 없습니다 - 어떤 생각입니까?

EDIT2 : Rhashimoto의 추천 당 , 나는 핸들러 추적을 활성화하고 로그에서이 기이을 발견하십시오 async_accept와 async_receive 사이에 700 밀리가 있습니다

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed) 
@asio|1373054319.874916|506*508|[email protected]_receive 
@asio|1373054319.874963|506*509|[email protected]_accept 
@asio|1373054319.875008|<506| 
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512 
@asio|1373054320.609233|508*510|[email protected]_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 

. 코드에서는 (http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.html의 "HTTP 서버 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 
     ) 
); 

하고 처음부터() :

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가 경과했습니다.

아무도 아이디어가 있습니까? 나는 완전히 잃어 버렸다.

감사합니다.

+0

실제로이 문제가 내 소켓 객체가 어떻게 든 사용 중이거나 과부하 상태가 될 수 있는지 궁금합니다. 그것은 OS 내에서가 아니므로 아마 내 프로그램의 다른 부분의 한가운데에있을 것입니다 .... 가능합니까? 그리고 async_read_until에서 지연이 발생할 수 있습니까? – Harry

+0

그리고 Keep-Alive 연결을 많이 사용하고 있습니다. 각 요청 후에 소켓 종료를 호출하면 안됩니까? – Harry

+1

우선, 성능 프로파일 러를 사용합니까? 그것은 무엇을 말하는가? –

답변

4

우리가 async_receive 두 번이라고 볼 수있는 로그에서

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed) 
@asio|1373054319.874916|506*508|[email protected]_receive 
@asio|1373054319.874963|506*509|[email protected]_accept 
@asio|1373054319.875008|<506| 
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512 
@asio|1373054320.609233|508*510|[email protected]_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 

로그 핸들러 볼 수 있습니다 : 첫 번째 734ms 핸들러 설정 (# 506) 후 (# 508)라고합니다. 이제 두 번째 async_receive은 핸들러 설정 (# 508) 후 53 마이크로 초 (# 510)에 호출됩니다. 데이터 (그 404 바이트)가 이미 TCP 스택에서 준비되었으므로 두 번째 처리기 호출이 빠르게 처리되었습니다.

결론 : 처리기 호출 지연이 아니라 전송 지연입니다. 아마 ISP 나 균형 조정 프로그램에 문제가 있거나 아마 Google이 요청에 불편을 끼쳐서 지연을 설정하고 싶지 않을 것입니다.

UPD : 나는 당신이 tcpdump

P.S.으로이를 확인할 수있을 것 같아요 HTTP 서버 2 예제에서 io_service_pool_ 구현을 좋아하지 않습니다. 이것도 몇 가지 문제가 발생할 수 있습니다,하지만 나는 그것의 현재 사건을 생각합니다.

+0

고마워, 나는이 방향으로 나의 더 깊은 연구를 설명하는 메인 포스트에 코멘트를 추가했다. 그리고 추신에 관해서는, io_service_pool 구현은 어떻습니까? 더 나은 성능을 위해 다른 디자인을 권장합니까? 이것이이 질문의 범위 밖에있는 영역이지만, 나는 약간의 통찰력에 대해 정말로 감사 할 것입니다. 감사! – Harry

+0

@Harry가 맨 위에 댓글에 답변했습니다. 정말로 지연 문제는 소프트웨어와 관련이없는 것 같습니다. io_service 풀에 관해서는 짧지 만,'io_service'의 인스턴스 하나가 오버로드되면 (또는 긴 작업을 실행하는 경우) -이 인스턴스의 모든 핸들러는 대기하고 차단됩니다. 의도적으로'io_service' 당 하나의 스레드 만 있기 때문입니다. 나는 1 개의'io_service'와 핸들러를 제공하는 쓰레드 풀을 실행하는 것을 선호한다. – PSIAlt