2008-09-27 5 views
7

Для программ, которые обрабатывают большое количество соединений сокетов (например, веб-сервисы, системы p2p и т. Д.), Доступно несколько вариантов.Как наиболее эффективно обрабатывать большое количество файловых дескрипторов?

  1. Создайте отдельный поток для ввода/вывода для каждого гнезда.
  2. Используйте системный вызов select для мультиплексирования ввода-вывода в один поток.
  3. Используйте системный вызов poll для мультиплексирования ввода/вывода (замена выбора).
  4. Используйте системные вызовы epoll, чтобы избежать повторной отправки сокетов fd через границы пользователя/системы.
  5. Создайте несколько потоков ввода-вывода, каждый из которых мультиплексирует относительно небольшой набор из общего количества соединений с использованием API опроса.
  6. Согласно №5, за исключением использования API epoll для создания отдельного объекта epoll для каждого независимого потока ввода-вывода.

На многоядерном процессоре я ожидал бы, что # 5 или # 6 будут иметь лучшую производительность, но у меня нет жестких данных, поддерживающих это. В поисковой сети появилась страница this, в которой рассказывается об опыте авторских подходов к тестированию № 2, № 3 и № 4 выше. К сожалению, этой веб-странице, похоже, около 7 лет, без каких-либо очевидных недавних обновлений.

Итак, мой вопрос в том, какие из этих подходов имеют люди, которые считаются наиболее эффективными и/или есть другой подход, который работает лучше, чем любой из перечисленных выше? Будут оценены ссылки на реальные графики, официальные документы и/или доступные в Интернете записи.

+0

Я думаю, что это решаемая проблема, и ответ здесь - http://www.kegel.com/c10k.html – computinglife 2008-09-27 01:26:32

ответ

0

Я использую epoll() широко, и он хорошо работает. Я регулярно подключаю тысячи сокетов и тестирую до 131 072 сокетов. И epoll() всегда может справиться с этим.

Я использую несколько потоков, каждый из которых опрошен на подмножестве сокетов. Это усложняет код, но в полной мере использует многоядерные процессоры.

2

По моему опыту, у вас будет лучший перфект с №6.

Я также рекомендую вам изучить libevent, чтобы иметь дело с абстрагированием некоторых из этих деталей. По крайней мере, вы сможете увидеть некоторые из их тестов benchmark results.

Кроме того, о том, сколько гнезд вы говорите? Ваш подход, вероятно, не имеет большого значения, пока вы не начнете получать хотя бы несколько сотен сокетов.

3

Говоря с моим опытом работы с большими IRC-серверами, мы использовали для использования select() и poll() (поскольку epoll()/kqueue() не были доступны). Около около 700 одновременных клиентов сервер будет использовать 100% CPU (сервер irc не был многопоточным). Однако, интересно, сервер будет работать хорошо. Около 4000 клиентов сервер начнет отставать.

Причина этого заключалась в том, что около 700 пользователей, когда мы вернемся к select(), будет доступен один клиент для обработки. Сканирование for(), чтобы выяснить, какой клиент он будет, будет потреблять большую часть процессора. Поскольку у нас появилось больше клиентов, мы бы стали получать все больше клиентов, нуждающихся в обработке, в каждом вызове select(), поэтому мы стали бы более эффективными.

Перемещение на epoll()/kqueue(), аналогичные специализированные машины будут тривиально иметь дело с 10 000 клиентов, с некоторыми (более мощными машинами, но все еще машинами, которые будут считаться крошечными по сегодняшним стандартам), провели 30 000 клиентов, не нарушая пота.

Эксперименты, которые я видел с SIGIO, похоже, показывают, что он хорошо работает для приложений, где латентность чрезвычайно важна, где есть только несколько активных клиентов, которые делают очень мало индивидуальной работы.

Я бы рекомендовал использовать epoll()/kqueue() над select()/poll() практически в любой ситуации. Я не экспериментировал с разделением клиентов между потоками. Честно говоря, я никогда не нашел службы, которая нуждалась в большей оптимизации работы над обработкой клиентского интерфейса, чтобы оправдать эксперименты с потоками.

2

Я провел 2 последних года, работая над этой конкретной проблемой (для веб-сервера G-WAN, который поставляется с МНОГИМИ бенчмарками и диаграммами, отображающими все это).

Модель, которая лучше всего работает под Linux, представляет собой epoll с одной очередью событий (и для интенсивной обработки, несколькими рабочими потоками).

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

Причина этого в том, что epoll не масштабируется на многоядерных процессорах (с использованием нескольких параллельных очередей epoll для подключения ввода/вывода в одном приложении с пользовательским режимом просто замедляет ваш сервер).

Я не смотрел серьезно на код epoll в ядре (пока я ориентирован только на пользовательский режим), но я предполагаю, что реализация epoll в ядре искалечена блокировками.

Именно поэтому использование нескольких потоков быстро ударило о стену.

Само собой разумеется, что такое плохое состояние не должно продолжаться, если Linux хочет сохранить свое положение как одно из лучших ядер.

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