2013-07-04 14 views
8

Alışılmadık bir sorun yaşıyorum. Bir C++ Boost.ASIO web sunucusu var ve bu kodu kullanıyorum gelen istekleri işlemek için:C++ Boost.ASIO async_read_until

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_" Benim boost :: asio :: ip :: tcp :: soket olduğu ve "response_" is bir boost :: asio :: streambuf)

Sadece istek başlıklarını yakalamaya çalışıyorum, daha sonra transfer edilen "İçerik Uzunluğu" ile transfer_exactly eşleştirerek ikinci bir async_read_until işlemi yapıyorum. istek başlığı. Sorun, yukarıdaki kodun çok modern bir sunucuya geri dönmesi için 100-900ms almasıdır (Bu okuma bloğundan, handle_read_headers() çağrılana kadar).

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) 

başlıkları bir \ r \ n \ r \ n ile sona gibi görünüyor ve yüzden değil (EOF'a tüm yol okumadan önce) (function handle_read_headers tetikleyebilir yapar: Gelen istek benziyor tüm sayfayı okurken) - aslında regex'i tetikliyor. Ve bu istekler Google'dan geliyor, bu yüzden onların sonlarında gecikme olmadığından eminim.

Geri dönmek için neden bu kadar uzun sürdüğüne baktığım bir şey var mı? Aync_read_until ile başka yakalar kaçırmış olabilirim?

Teşekkürler!

DÜZENLEME/GÜNCELLEME: Tamam, şimdi kafam çok kafam karıştı. Megabyte'ın önerisini denerken, streambuf'tan bir karakter dizisine geçtim (şans yok), daha sonra async_read_until yerine async_read_some kullanmak için kodumu yeniden düzenledim ve sadece sınırlandırılmış el ile taramaya başladım. Ayrıca tüm OS değişkenlerini (sysctrl.conf) kemik stoğu varsayılanına (olasılıkları daraltmak için) sıfırlarım. response_ şimdi

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

geçerli:: Maalesef hala aynı gelen POST isteği ile) (handle_read çağırarak aşağıdaki kodda 100-900ms gecikmeler görüyorum boşuna için

boost::array<char, 4096> response_; 

(aynı 100-900ms gecikmeler). Bunun normal bir yolu yok - herhangi bir düşünce?

EDIT2: Rhashimoto önerisi Başına , ben işleyici izlemeyi etkinleştirdikten ve günlüğünde bu gariplik bulundu: async_accept ve async_receive arasında 700 milisaniye boyunca var

[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 

. kodunda, o (http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.html ait "HTTP Sunucusu 2" neredeyse düz - server.cpp ve connection.cpp) Bu bloğun gider: için

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

ve baştan():

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

ve handle_read_headers() çağrıldığında, 700 msn geçmiştir.

Herhangi bir fikri olan var mı? Tamamen kayboldum.

Çok teşekkürler!

+0

Aslında bunun soket nesnesinin bir şekilde meşgul olmasından kaynaklanabileceğini merak ediyorum (veya aşırı yüklenmiş). İşletim sistemi içinde değil, belki de programımdaki başka bir şeyin ortasında olabilir ... bu mümkün mü? Ve bu async_read_until üzerinde bir gecikme neden olabilir mi? – Harry

+0

Ve Keep-Alive bağlantıları ile yoğun bir şekilde çalışıyorum - her istekten sonra bir soket kapatma yapmamalı mıyım (yoksa normal mi)? – Harry

+1

Her şeyden önce, bir performans uzmanı kullanıyor musunuz? Ne diyor? –

cevap

4

biz async_receive iki kez denir görebilirsiniz günlükten

[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 

log işleyicileri inceleyelim: İlk 734ms işleyici kurulum (# 506) sonra (# 508) olarak adlandırılır. Şimdi, ikinci async_receive işleyici kurulumundan (# 508) sonra 53 mikrosaniye (# 510) çağrılır. Yani, ikinci işleyici çağrısı hızlıca ateşlendi çünkü veriler (404 bayt) TCP yığınında zaten hazırdı.

Sonuç: Bu bir işleyici çağrısı gecikmesi değil, taşıma gecikmesi. Muhtemelen ISS veya bir dengeleyici ile ilgili sorun, ya da belki Google gerçekten isteklerinizi ve gecikmeleri ayarlayarak sizi rahatsız etmek istemiyor.

UPD: Sana tcpdump

P.S. ile kontrol edebilirsiniz düşünüyorum HTTP sunucusu 2 örneğindeki io_service_pool_ uygulamasını sevmiyorum. Bu da bazı sorunlara neden olabilir, ama mevcut durumda değil düşünüyorum.

+0

Teşekkürler, daha sonra bu yöndeki araştırmamı açıklayan ana yazıya bir yorum ekledim. Ve PS ile ilgili olarak, io_service_pool uygulama hakkında ne? Daha iyi performans için farklı bir tasarım önerir misiniz? Bu sorunun kapsamı dışında kalan bir alan var, ama bazı içgörüyü gerçekten takdir ediyorum. Teşekkürler! – Harry

+0

@Harry, üstteki yorumu yanıtladı. Gerçekten gecikme sorunu yazılımla ilgili değil gibi görünüyor. Hakkında io_service havuzu uzun hikaye ama kısaca: Eğer io_service' bir kez aşırı yüklenirse (ya da uzun çalışma işi yürütür) - Bu örnekte tüm işleyicileri beklemek ve engellenir, çünkü tasarım gereği her 'io_service' başına sadece 1 iş parçacığı vardır. Ben 1 'io_service' ve işleyicilerine hizmet veren bir iş parçacığı havuzu çalıştırmayı tercih ediyorum. – PSIAlt