2013-02-25 3 views
11

Я реализую настраиваемый сервер, который должен поддерживать очень большое количество (100 тыс. Или более) долгоживущих соединений. Сервер просто передает сообщения между сокетами и не выполняет никакой серьезной обработки данных. Сообщения небольшие, но многие из них принимаются/отправляются каждую секунду. Одной из целей является сокращение латентности. Я понимаю, что использование нескольких ядер не улучшит производительность, поэтому я решил запустить сервер в одном потоке, вызвав run_one или poll методы объекта io_service. В любом случае многопоточный сервер будет намного сложнее реализовать.Boost Asio single threaded performance

Каковы возможные узкие места? Syscalls, пропускная способность, завершение очереди/демультиплексирование событий? Я подозреваю, что диспетчерам диспетчеризации может потребоваться блокировка (что делается внутри библиотеки asio). Можно ли отключить даже блокировку очередей (или любую другую блокировку) в boost.asio?

EDIT: родственный вопрос. Улучшена ли производительность системы syscall с несколькими потоками? Я чувствую, что из-за того, что syscalls атомарно/синхронизировано ядром, добавление большего количества потоков не улучшит скорость.

+0

Если вы используете все в одном потоке, вам не нужны никакие (рукописные) блокировки. –

+1

Использование нескольких ядер, вероятно, улучшит производительность - см. Http://cmeerw.org/blog/748.html#748 и http://cmeerw.org/blog/746.html#746 для некоторых тестов, которые я сделал в прошлом году. – cmeerw

ответ

15

Возможно, вы хотели бы прочитать my question несколько лет назад, я попросил его сначала изучить масштабируемость Boost.Asio при разработке системного программного обеспечения для Blue Gene/Q supercomputer.

Масштабирование до 100 тыс. Или более соединений не должно быть проблемой, хотя вам необходимо знать очевидные ограничения ресурсов, такие как максимальное количество дескрипторов открытых файлов. Если вы не прочитали семена C10K paper, я предлагаю прочитать его.

После реализации приложения с помощью одной нити и одного io_service, я предлагаю исследование пула потоков, ссылающихся io_service::run(), и только затем исследовать прижав к io_service к определенной теме и/или центральному процессору. Есть несколько примеров, включенных в документацию Asio для всех трех этих проектов, и several questions на SO с дополнительной информацией.Имейте в виду, что при вводе нескольких потоков, вызывающих io_service::run(), вам может потребоваться реализовать strand s, чтобы обеспечить, чтобы обработчики имели эксклюзивный доступ к общим структурам данных.

9

Использование boost :: asio позволяет писать серверы с одним потоком или несколькими потоками примерно с одинаковой стоимостью разработки. Вы можете написать однопоточную версию в качестве первой версии, а затем преобразовать ее в многопоточную, если необходимо.

Как правило, только узким местом для повышения: asio является то, что epoll/kqueue Реактор работает в мьютексе. Таким образом, только один поток выполняет epoll одновременно. Это может снизить производительность в случае, если у вас многопоточный сервер, который обслуживает партии и много очень маленьких пакетов. Но, imo это в любом случае должно быть быстрее, чем простой однопоточный сервер.

Теперь о вашей задаче. Если вы хотите просто передавать сообщения между соединениями - я думаю, это должен быть многопоточный сервер. Проблема заключается в syscalls (recv/send и т. Д.). Команда очень легко думать о процессоре, но любой syscall не очень «легкий» (все относительно, но относительно других заданий в вашей задаче). Таким образом, с одним потоком вы получите большие системные расходы накладные расходы, поэтому я рекомендую использовать многопоточную схему.

Кроме того, вы можете разделить io_service и заставить его работать как идиома «io_service per thread». Я думаю, что это должно дать лучшую производительность, но у него есть недостаток: если один из io_service получит слишком большую очередь - другие потоки не помогут, поэтому некоторые подключения могут замедлить работу. С другой стороны, с одним io_service - переполнение очереди может привести к большим накладным расходам. Все, что вы можете сделать - сделать оба варианта и измерить полосу пропускания/задержки. Не сложно реализовать оба варианта.