2016-11-29 3 views
3

Я новичок в boost :: asio. Попытка запуститьСервер зависает, пока после 16000 запросов

ab -n 20000 -c 5 -r http://127.0.0.1:9999/ 

Испытание застревает после запроса 16000 каждый раз. Но это действительно так. Также я получаю много неудавшегося запроса.

Какой код делает:

  • A. Создание службы
  • B. Создание Acceptor
  • C. Bind и слушать
  • D. создать сокет
  • F. Do async_connect
  • G. В обработчике async_connect close socket. Создать новый и сделать async_connect с тем же обработчиком.

код следующим образом:

#include <iostream> 
#include <functional> 
#include <string> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/thread.hpp> 
#include <memory> 

// global variable for service and acceptor 
boost::asio::io_service ioService; 
boost::asio::ip::tcp::acceptor accp(ioService); 

// callback for accept 
void onAccept(const boost::system::error_code &ec, shared_ptr<boost::asio::ip::tcp::socket> soc) { 
    using boost::asio::ip::tcp; 
    soc->send(boost::asio::buffer("In Accept")); 
    soc->shutdown(boost::asio::ip::tcp::socket::shutdown_send); 
    soc.reset(new tcp::socket(ioService)); 
    accp.async_accept(*soc, [=](const boost::system::error_code &ec) { 
      onAccept(ec, soc); 
     }); 
} 

int main(int argc, char *argv[]) { 
    using boost::asio::ip::tcp; 
    boost::asio::ip::tcp::resolver resolver(ioService); 
    try { 
     boost::asio::ip::tcp::resolver::query query("127.0.0.1", boost::lexical_cast<std::string>(9999)); 
     boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 
     accp.open(endpoint.protocol()); 
     accp.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 
     accp.bind(endpoint); 
     cout << "Ready to accept @ 9999" << endl; 

     auto t1 = boost::thread([&]() { ioService.run(); }); 

     accp.listen(boost::asio::socket_base::max_connections); 
     std::shared_ptr<tcp::socket> soc = make_shared<tcp::socket>(ioService); 

     accp.async_accept(*soc, [=](const boost::system::error_code &ec) { onAccept(ec, soc); }); 

     t1.join(); 
    } catch (std::exception &ex) { 
     std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; 
    } 
} 

Для полноты:

  1. я изменил свой код в соответствии с @Arunmu
  2. Я использовал докер с Linux из-за проблемы сокета предложенному @ Давид- schwartz
  3. Сервер никогда не висит сейчас.
    • Single Thread - 6045 REQ в секунду
    • Темы - 5849 REQ в секунду
  4. Использование async_write
+1

Ваш код переходит в бесконечную рекурсию до исчерпания стека. Рекурсия в 'onAccept' должна быть заменена чем-то правильным – GMichael

+0

, это обычный способ для асинхронного программирования. Если я этого не сделаю, не будет никакого обработчика. Он может выглядеть рекурсивно, но не так, как async_accept возвращает сразу, то есть без вызова чего-либо. –

+0

В этом случае установите ограничение на рекурсию. Как глубина звонков. – GMichael

ответ

2

У вас заканчиваются локальные розетки. Вы не должны тестировать, генерируя всю нагрузку с одного IP-адреса. (Кроме того, ваш генератор нагрузки должен быть достаточно умным, чтобы обнаруживать и обойти это условие, но, к сожалению, многие из них не являются.)

3

Прежде всего, давайте делать вещи бит более правильно. Я изменил код, чтобы использовать автономный asio вместо boost и использовать C++ 14 feature (s). С вашим сырым кодом было много неудач, которые я уменьшил с моими изменениями.

Код:

#include <iostream> 
#include <functional> 
#include <string> 
#include <asio.hpp> 
#include <thread> 
#include <memory> 
#include <system_error> 
#include <chrono> 

//global variable for service and acceptor 
asio::io_service ioService; 
asio::ip::tcp::acceptor accp(ioService); 

const char* response = "HTTP/1.1 200 OK\r\n\r\n\r\n"; 

//callback for accept 
void onAccept(const std::error_code& ec, std::shared_ptr<asio::ip::tcp::socket> soc) 
{ 
    using asio::ip::tcp; 
    soc->set_option(asio::ip::tcp::no_delay(true)); 
    auto buf = new asio::streambuf; 
    asio::async_read_until(*soc, *buf, "\r\n\r\n", 
     [=](auto ec, auto siz) { 
      asio::write(*soc, asio::buffer(response, std::strlen(response))); 
      soc->shutdown(asio::ip::tcp::socket::shutdown_send); 
      delete buf; 
      soc->close(); 
     }); 
    auto nsoc = std::make_shared<tcp::socket>(ioService); 
    //soc.reset(new tcp::socket(ioService)); 
    accp.async_accept(*nsoc, [=](const std::error_code& ec){ 
     onAccept(ec, nsoc); 
    }); 

} 

int main(int argc, char * argv[]) 
{ 
    using asio::ip::tcp; 
    asio::ip::tcp::resolver resolver(ioService); 

    try{ 
     asio::ip::tcp::resolver::query query( 
      "127.0.0.1", 
      std::to_string(9999) 
     ); 

    asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 
    accp.open(endpoint.protocol()); 
    accp.set_option(asio::ip::tcp::acceptor::reuse_address(true)); 
    accp.bind(endpoint); 

    std::cout << "Ready to accept @ 9999" << std::endl; 

    auto t1 = std::thread([&]() { ioService.run(); }); 
    auto t2 = std::thread([&]() { ioService.run(); }); 

    accp.listen(1000); 

    std::shared_ptr<tcp::socket> soc = std::make_shared<tcp::socket>(ioService); 

    accp.async_accept(*soc, [=](const std::error_code& ec) { 
           onAccept(ec, soc); 
           }); 

    t1.join(); 
    t2.join(); 
    } catch(const std::exception & ex){ 
     std::cout << "[" << std::this_thread::get_id() 
     << "] Exception: " << ex.what() << std::endl; 
    } catch (...) { 
     std::cerr << "Caught unknown exception" << std::endl; 
    } 
} 

Основные изменения:

  1. Отправить надлежащий ответ HTTP.
  2. Просьба. В противном случае вы просто заполняете свой буфер приема сокетов.
  3. Правильный разъем близко.
  4. Использование нескольких потоков. Это в основном требовалось для Mac OS, не требуемое для Linux. Команда

Тест используется: ab -n 20000 -c 1 -r http://127.0.0.1:9999/

На Linux, тест пройден без ошибок довольно быстро и без использования дополнительных потоков для io_service.

Но, на Mac Я смог воспроизвести проблему i.e он застревает после обработки 16000 запросов. Пробу процесс в этот момент является:

Call graph: 
    906 Thread_1887605 DispatchQueue_1: com.apple.main-thread (serial) 
    + 906 start (in libdyld.dylib) + 1 [0x7fff868bc5c9] 
    + 906 main (in server_hangs_so) + 2695 [0x10d3622b7] 
    +  906 std::__1::thread::join() (in libc++.1.dylib) + 20 [0x7fff86ad6ba0] 
    +  906 __semwait_signal (in libsystem_kernel.dylib) + 10 [0x7fff8f44c48a] 
    906 Thread_1887609 
    + 906 thread_start (in libsystem_pthread.dylib) + 13 [0x7fff8d0983ed] 
    + 906 _pthread_start (in libsystem_pthread.dylib) + 176 [0x7fff8d09afd7] 
    +  906 _pthread_body (in libsystem_pthread.dylib) + 131 [0x7fff8d09b05a] 
    +  906 void* std::__1::__thread_proxy<std::__1::tuple<main::$_2> >(void*) (in server_hangs_so) + 124 [0x10d36317c] 
    +   906 asio::detail::scheduler::run(std::__1::error_code&) (in server_hangs_so) + 181 [0x10d36bc25] 
    +   906 asio::detail::scheduler::do_run_one(asio::detail::scoped_lock<asio::detail::posix_mutex>&, asio::detail::scheduler_thread_info&, std::__1::error_code const&) (in server_hangs_so) + 393 [0x10d36bfe9] 
    +    906 kevent (in libsystem_kernel.dylib) + 10 [0x7fff8f44d21a] 
    906 Thread_1887610 
     906 thread_start (in libsystem_pthread.dylib) + 13 [0x7fff8d0983ed] 
     906 _pthread_start (in libsystem_pthread.dylib) + 176 [0x7fff8d09afd7] 
      906 _pthread_body (in libsystem_pthread.dylib) + 131 [0x7fff8d09b05a] 
      906 void* std::__1::__thread_proxy<std::__1::tuple<main::$_3> >(void*) (in server_hangs_so) + 124 [0x10d36324c] 
       906 asio::detail::scheduler::run(std::__1::error_code&) (in server_hangs_so) + 181 [0x10d36bc25] 
       906 asio::detail::scheduler::do_run_one(asio::detail::scoped_lock<asio::detail::posix_mutex>&, asio::detail::scheduler_thread_info&, std::__1::error_code const&) (in server_hangs_so) + 263 [0x10d36bf67] 
        906 __psynch_cvwait (in libsystem_kernel.dylib) + 10 [0x7fff8f44c136] 

Total number in stack (recursive counted multiple, when >=5): 

Sort by top of stack, same collapsed (when >= 5): 
     __psynch_cvwait (in libsystem_kernel.dylib)  906 
     __semwait_signal (in libsystem_kernel.dylib)  906 
     kevent (in libsystem_kernel.dylib)  906 

только после предоставления дополнительной нити, я был в состоянии получить тест в комплекте с ниже результата:

Benchmarking 127.0.0.1 (be patient) 
Completed 2000 requests 
Completed 4000 requests 
Completed 6000 requests 
Completed 8000 requests 
Completed 10000 requests 
Completed 12000 requests 
Completed 14000 requests 
Completed 16000 requests 
Completed 18000 requests 
Completed 20000 requests 
Finished 20000 requests 


Server Software: 
Server Hostname:  127.0.0.1 
Server Port:   9999 

Document Path:  /
Document Length:  2 bytes 

Concurrency Level:  1 
Time taken for tests: 33.328 seconds 
Complete requests:  20000 
Failed requests:  3 
    (Connect: 1, Receive: 1, Length: 1, Exceptions: 0) 
Total transferred:  419979 bytes 
HTML transferred:  39998 bytes 
Requests per second: 600.09 [#/sec] (mean) 
Time per request:  1.666 [ms] (mean) 
Time per request:  1.666 [ms] (mean, across all concurrent requests) 
Transfer rate:   12.31 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 0 30.7  0 4346 
Processing:  0 1 184.4  0 26075 
Waiting:  0 0 0.0  0  1 
Total:   0 2 186.9  0 26075 

Percentage of the requests served within a certain time (ms) 
    50%  0 
    66%  0 
    75%  0 
    80%  0 
    90%  0 
    95%  0 
    98%  0 
    99%  0 
100% 26075 (longest request) 

Stack след нити, которая была, вероятно, застрял :

* thread #3: tid = 0x0002, 0x00007fff8f44d21a libsystem_kernel.dylib`kevent + 10, stop reason = signal SIGSTOP 
    * frame #0: 0x00007fff8f44d21a libsystem_kernel.dylib`kevent + 10 
    frame #1: 0x0000000109c482ec server_hangs_so`asio::detail::kqueue_reactor::run(bool, asio::detail::op_queue<asio::detail::scheduler_operation>&) + 268 
    frame #2: 0x0000000109c48039 server_hangs_so`asio::detail::scheduler::do_run_one(asio::detail::scoped_lock<asio::detail::posix_mutex>&, asio::detail::scheduler_thread_info&, std::__1::error_code const&) + 393 
    frame #3: 0x0000000109c47c75 server_hangs_so`asio::detail::scheduler::run(std::__1::error_code&) + 181 
    frame #4: 0x0000000109c3f2fc server_hangs_so`void* std::__1::__thread_proxy<std::__1::tuple<main::$_3> >(void*) + 124 
    frame #5: 0x00007fff8d09b05a libsystem_pthread.dylib`_pthread_body + 131 
    frame #6: 0x00007fff8d09afd7 libsystem_pthread.dylib`_pthread_start + 176 
    frame #7: 0x00007fff8d0983ed libsystem_pthread.dylib`thread_start + 13 

Это может, вероятно, проблема с kqueue_reactor реализации в asio или в самой системе макинтош (менее вероятно)

ОБНОВЛЕНИЕ: Такое же поведение наблюдается и с libevent. Итак, не проблема с реализацией asio. Это должно быть некоторая ошибка в реализации ядра kqueue. Проблема не встречается с epoll на linux.

+0

очень хорошее исследование. –

+0

После чистки розетки я не получаю никаких сбоев. Даже с 2 потоками в процессе Mac зависает, пока около 16K req. Будет обновление, если я что-то найду. Благодаря !!! –

+0

@ VishalKumar Ответ Давида правильный. Примите, что вместо этого. – Arunmu

Смежные вопросы