| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Сети > Оценка эффективности ASIO сервера |
| Автор: rumit7 20.10.2011, 21:12 | ||
| Здравствуйте! В данный момент активно занялся изучением возможностей Boost::ASIO. Впечатления от самой библиотеки только самые положительные, давно мне так сильно ничего не нравилось, наверно с тех самых пор, как я познакомился с С++, лет так 8 назад) Изучая http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/examples.html, http://sourceforge.net/projects/asio-samples/files/asio-samples/, а также другие примеры в сети, задумался над выработкой критериев для сравнения различных моделей построения асинхронного сервера, таких как (простите, не знаю как лучше перевести на русский):
На данный момент меня интересует - преимущества и недостатки каждой из моделей, на основе чего можно было бы сделать выбор под конкретные требования сервера.. Я так понимаю, наиболее важные критерии это:
Как правильнее оценить? Что обычно применяют в таких случаях? Какие-то утилиты вроде Jmeter? Или что-то еще? Обращаюсь к Вам с просьбой помочь разобраться в теме.. Пока сам пробую применить самописный многопоточный клиент - клиент запускает указанное кол-во потоков, каждый из которых одновременно начинает соединяться с сервером и собирает временную статистику. Ниже привожу код данного эхо клиента.
|
| Автор: boostcoder 21.10.2011, 01:05 |
| rumit7, слишком уж абстрактно все у вас описано. можно долго распинаться описывая для вас то, что перепечатано во множестве книжек. поконкретнее вопросы, пожалуйста. |
| Автор: rumit7 21.10.2011, 06:11 | ||
На данный момент меня интересует - скорость обработки запроса. Т.е. каким образом правильнее организовать сравнение по скорости обработки различных примеров, приводимых в ASIO Examples, ASIO Samples. Будут ли достоверными данные предоставляемые выше приведенной самописной тестовой тулзой? |
| Автор: rumit7 21.10.2011, 06:46 | ||||||||||||
Я так понимаю здесь возможно использование memory pool на каждый проц и плюс к этому использование custom memory allocation, чтобы исключить обращение к общей памяти при выполнении асинхронных операций?
Спасибо. Пока моя цель - "быстро и масштабируемо", но по возможности с использованием ASIO. А там будем делать выводы..
Это модель применена в ASIO Samples, когда один io_service (+ 1 или 2 потока) используется для акцепта клиентов, создания сессий и управления ими, а второй io_service (+ по потоку на каждый проц) используется всеми сессиями (т.е. взаимодействие с клиентами).
Да я это понимаю. На данный момент я бы хотел выяснить: какой из моделей способов использования ASIO библиотеки дает больший перформанс и в каких случаях? Просто сравнивать примеры эхо серверов это глупо, яный пень в реальном проекте гораздо больше взаимодействий между различными факторами.. Но нужно же как-то выбрать. Следовательно нужно выполнить сравнение прототипов, думаю на первом этапе по скорости обработки клиентов. Здесь у меня начинается ступор - как лучше организовать сравнительный тест?
Спасибо за Ваш ответ! |
| Автор: rumit7 21.10.2011, 07:42 | ||||
Из документации Boost::ASIO:
Это ведь значит, что и с использованием ASIO можно добиться "что-бы вся бизнес логика была в одном потоке, на одном ядре, а весь I/O был асинхронным"? |
| Автор: boostcoder 21.10.2011, 07:44 | ||||
я и сам использую реализацию из https://sourceforge.net/projects/asio-samples/ построенную на этой архитектуре, и, мое имхо - это лучшая архитектура. т.к. обладает высокой скоростью accepta+reusing_sessions, что позволит пережить большинство DDOS атак, так и тем что второй io_service существует в единственном экземпляре, что позволяет при использовании strand`ов избавится от прямой необходимости в синхронизации. ну а тестирование_производительности/сравнение_производительности - это очень субъективно и зависимо... Добавлено через 3 минуты и 30 секунд
да. при использовании двух и более io_service`ов. но в этом случае всю синхронизацию придется обеспечивать руками. а в этом случае, не факт что такая архитектура будет обладать большей производительностью. |
| Автор: rumit7 21.10.2011, 08:08 | ||
Я хочу объеденить два подхода: показанный в примерах https://sourceforge.net/projects/asio-samples/ и io_service на каждый проц. Идея заключается в том, чтобы по возможности локализовать обращение к памяти внутри одного проца (потока). Для этого выделять память, как для объектов сессий, так и для каждой асинхронной операции (custom memory allocation) - память из memory pool? При этом, чтобы исключить синхронизацию между потоками, создать для каждого потока свой memory pool. Возможно использовать вместо shared_ptr - intrusive_ptr. При все этом не потерять преимущества архитектуры использованной в asio-samples, насколько это вообще технически возможно.. А вот чтобы сравнить две модели мне и нужно иметь какую-то тестовую тулзу + сценарий выполнения тестов.. |
| Автор: boostcoder 21.10.2011, 08:20 | ||
грубо говоря - да. но можно иначе: кол-во сессий обычно ограниченно сверху. т.е. можно просто создать пул сессий, к примеру по максимуму, 65К, и поместить их в какой-то recycled-buffed/queue. каждая сессия содержит свои аллокаторы для custom_memory_allocation. таким образом полностью пропадает необходимость в memory_pool для служебных данных(собственно asio-samples и их echo_server так(ну, почти так) и реализован). но остаются еще буфера для пользовательских данных... |
| Автор: rumit7 21.10.2011, 08:27 | ||
Да у меня возникла такая-же идея при изучении примеров из asio-samples. Если, как Вы говорите, преаллоцировать память для всех сессий, то соответственно упростится та схема, которую я описал выше. Следовательно остается только memory_pool-ы для пользовательских данных.. Над этим нужно подумать.. Спасибо! |
| Автор: boostcoder 21.10.2011, 08:40 | ||
тут можно поступить следующим образом, влоб: т.к. кол-во асинхронных операций так же ограничено сверху двумя, то в объекте сессии, так же можно предаллоцировать их, выбрав при этом необходимый объем. к примеру 32к. и того: WA+RA+TA+WB+RB*65к=~4Gb где: WA - allocator for write handlers(http://asio-samples.svn.sourceforge.net/viewvc/asio-samples/trunk/include/ma/echo/server/session.hpp?revision=523&view=markup) RA - allocator for read handlers(http://asio-samples.svn.sourceforge.net/viewvc/asio-samples/trunk/include/ma/echo/server/session.hpp?revision=523&view=markup) TA - allocator for timer handlers(http://asio-samples.svn.sourceforge.net/viewvc/asio-samples/trunk/include/ma/echo/server/session.hpp?revision=523&view=markup) WB - allocator for write buffer RB - allocator for read buffer но, в реале сессий все же меньше. Добавлено @ 08:50 собственно, такой способ преаллокации_всего дает два плюса: 1)устраняет проблему фрагментации памяти, 2)устраняет run-time оверхед memory_poll`ов. Up. и 4Gb для подобных задач - совсем не много. на самом деле, сессий все же меньше 65к, т.к. часть портов зарезервирована_системой/занята_другими_программами. |
| Автор: rumit7 21.10.2011, 09:03 | ||||||
Спасибо! Вот только как эта массовая предаллокация скажется на других задачах выполняющихся на сервере? У нас например возможна ситуация, когда на одном и том-же железе работать будет как наш сервер-приложение, так и стороннее приложение, в взаимодействии с которым мы фактически и выполняем работу..
Но ведь использование memory-pool также решает проблему фрагментации памяти, а run-time оверхед не такой уж и большой, если исключить синхронизацию между потоками!? При этом memory pool можно настроить таким образом, чтобы лишняя память освобождалась.. |
| Автор: boostcoder 21.10.2011, 09:07 | ||||||
никак
и
= противоречие. это зависит... но он есть. мое скромное имхо - я бы вовсе не заморачивался с экономией памяти, т.к. 16Gb это не какой-то космический объем. |
| Автор: rumit7 21.10.2011, 09:19 | ||||||||
Здесь я имел ввиду следующее - если в пик активности сервера памяти в memory pool не достаточно, то соот. выделяется еще один дополнительный блок (может быть даже х2 размера от предыдущего) и так циклически; после того как активность спадает, то из всего этого выделенного пространства будет реально использоваться куда меньше.. Так вот этот излишек можно вернуть (разумеется оставить с запасом), чтобы избежать свопинга..
Спасибо большое! |
| Автор: mabrarov 21.10.2011, 09:28 | ||
Стратегию "io_service per CPU" вроде как используют в Yandex. Она позволяет исключить миграцию, например, экземпляров ma::echo::server::session между кэшами разных ядер/процессоров. Т.е. все ma::echo::server::session, относящиеся к одному экземпляру io_service, теоретически могут влезть (и не вылазить от туда в течение всей работы) в кэш одного ядра. Кроме того, это избавляет от необходимости защищать ma::echo::server::session при помощи io_service::strand (который тоже не бесплатно дается и ОС и процессору). Я подумывал дать возможность в echo_server использовать такую стратегию для ma::echo::server::session (указывая это как параметр CLI). Но пока не решил вопрос с рапределением ma::echo::server::session по набору экземпляров io_service. Здесь нужна какая-то статистика с каждого io_service, которая тоже будет отнимать ресурсы и время. Стратегии "single io_service + thread pool" и "one io_service for session manager + one io_service for all sessions" почти одно и то же. Во втором случае ma::echo::server::session_manager вынесен отдельно аля SEDA. Это сделано для гарантии того, что даже при максимальной загрузке ma::echo::server::session_manager (простейшая DOS-атака) на обработку сессий будет потрачено не менее определенной части всего процессорного времени, выделенного на процесс сервера. Ну и да, тестировать и еще раз тестировать. "Золотая тропа" известна: make it build and work, make it work right, if need (!) make it (more) fast. Стратегия "one io_service for session manager + one io_service for all sessions" остановилась на втором шаге. Возможно, на третьем шаге стратегия "io_service per CPU" победит. Однако, эффективная реализация "io_service per CPU" м/б сложнее "one io_service for session manager + one io_service for all sessions". |
| Автор: mabrarov 21.10.2011, 09:50 |
| http://asio-samples.blogspot.com/2011/09/echoserver-revisited.html?showComment=1319179597404#c1866277865684306536. |
| Автор: Lazin 21.10.2011, 10:07 | ||||||
стратегию io_service per cpu можно использовать, если одна сессия часто обращается к одним и тем же данным, что-бы кэширование имело смысл, и при этом не выполняет ничего тяжелого. Под тяжелым я имею ввиду продолжительные вычисления, если одна сессия займет процессора на 1мс то ни одна другая сессия, выполняемая на этом io_service-е не сможет ничего сделать в течении этой милисекунды. А в случае пулла потоков это не так, одна из сессий заняла поток на 1мс, все остальные продолжают работать на оставшихся N потоках.
Для того, что-бы это было похоже на SEDA нужно еще много чего сделать
Что-бы об этом рассуждать, нужно хоть что-нибудь знать о проблеме. Может быть не победит, может быть вообще победит thread per session Добавлено через 1 минуту и 48 секунд вообще, если клиентов не много, то асинхронный сервер будет иметь более низкую пропускную способность, нежели простой thread per client сервер выполняющий все операции ввода/вывода синхронно, ибо во втором случае будет меньше системных вызовов |
| Автор: boostcoder 21.10.2011, 10:16 |
"staged event-driven architecture" ? |
| Автор: mabrarov 21.10.2011, 10:24 | ||||||||||
Не путаем исходящие TCP соединения и входящие 8) Кол-во входящих ограничено ресурсами ОС (и локальный порт у них у всех один - тот с которого соединение было accepted, т.е. тот, что у listening socket). Кол-во исходящих соединений ограничено еще и максимальным кол-вом открытых портов, http://en.wikipedia.org/wiki/Ephemeral_port. Вот. Заодно и вспомнил теорию. Добавлено @ 10:27
Конечно, предполагается, что тяжелой работой будет заниматься другой пул потоков. Добавлено @ 10:28
Да Добавлено @ 10:31
Естественно, это далеко от SEDA в том виде, как она описана в теории. Но смысл аналогичный - разбиваем обработку на стадии. На каждой стадии м/б свой пул потоков. Добавлено @ 10:33
Опять, "естественно" да. Эта теория проштудирована много раз. Все же, думаю, здесь рассматривается случай с (большим) множеством клиентов. |
| Автор: rumit7 21.10.2011, 10:36 | ||||||||
Спасибо за пояснения!
Там я указал:
Можно сказать ресерч возможностей каждой из моделей, чтобы иметь информацию для выбора под конкретные требования..
Да. Моя вина - изначально не четко сформулировал вопрос.. |
| Автор: mabrarov 21.10.2011, 10:38 | ||
Оформить бы выводы в виде FAQ и засунуть в документацию Asio. |
| Автор: Lazin 21.10.2011, 10:51 | ||||
все равно это сложнее, нужно решить проблему балансирования нагрузки между отдельными io_service-ами
большой - понятие растяжимое |
| Автор: mabrarov 21.10.2011, 10:56 | ||
О том я и писал в своем первом сообщении. |
| Автор: mabrarov 23.10.2011, 09:18 |
| http://www.jabberdoc.org/section13. Мало и, возможно, не то, что нужно было. Но интересно. |
| Автор: rumit7 23.10.2011, 10:54 | ||
Спасибо за ссылку! Я пока обнумываю все то, что здесь говорилось. В принципе есть идея того, как используя memory pool ускорить выделение памяти и помочь стратегии io_service per cpu в плане кеширования.. Есть ряд проблем, если удастся достичь положительного результата - отпишусь здесь.. Если нет, наверно промолчу, умнее казаться буду)) |
| Автор: Олег2005 26.10.2011, 23:09 |
| Модератор: хочу отметить высокий профессионализм участников темы - и пожелать им еще больших успехов в нашем непростом сетевом программировании |