C: epoll и многопоточность

Мне нужно создать специализированный HTTP-сервер, для этого я планирую использовать epoll sycall, но я хочу использовать несколько процессоров/ядер и не могу придумать архитектурное решение. ATM моя идея следующая: создать несколько потоков с собственными дескрипторами epoll, основной поток принимает соединения и распределяет их между потоками epoll. Но есть ли лучшие решения? Какие книги/статьи/руководства я могу прочитать по архитектуре с высокой нагрузкой? Я видел только статью C10K, но большинство ссылок на примеры мертвы :( и до сих пор нет в -глубокие книги на эту тему :(.

Спасибо за ответы.

UPD: Пожалуйста, будьте более конкретными, мне нужны материалы и примеры (nginx не является примером, потому что он слишком сложен и имеет несколько уровней абстракции для поддержки нескольких систем).


person Daniel    schedule 14.01.2011    source источник
comment
Привет, Даниэль, мне было интересно, как это продвигается. Я провожу некоторые исследования по этому вопросу, и я считаю, что моя концепция серверов, управляемых событиями, может быть немного слабой прямо сейчас. Насколько мне известно, кажется, что если у нас есть серверная часть, управляемая событиями (скажем, с использованием epoll), каждая вызываемая функция должна быть неблокирующей... может быть, это мой дизайн, но каждый поступающий запрос вызывает вызов базы данных. если этот вызов по какой-либо причине медленный, все другие клиенты, выполняющие запросы в то же время, также страдают из-за ожидания завершения ответа базы данных. Я могу создать нить .. побеждает цель.   -  person Begui    schedule 10.03.2012
comment
на самом деле его не будет, он давно закончен с использованием libev :) некоторые функции все еще блокируются в моем приложении, просто их время блокировки очень мало. но такие вещи, как запросы к базе данных, операции ввода-вывода (особенно когда они действительно интенсивны) должны быть неблокирующими. в моем случае я использую mongodb с его асинхронным драйвером, поэтому у меня нет блокировок при использовании db. у меня есть пулы потоков для вещей, которые я не мог сделать асинхронными (например, обработка изображений ImageMagick и минимизаторы CSS/JS), но они работают через очереди и контролируются epoll (собственная реализация очереди).   -  person Daniel    schedule 12.03.2012


Ответы (3)


проверьте libevent и libev. они легко читаются и уже представляют собой хорошую инфраструктуру для использования.

Кроме того, в документации libev есть множество примеров нескольких проверенных стратегий. Даже если вы предпочитаете писать напрямую epoll(), примеры могут привести к некоторым выводам.

person Javier    schedule 14.01.2011
comment
из того, что я вижу, libevent однопоточный, но очень эффективный. не могу найти примеры libevent + multithreading atm, но гуглю в процессе... - person Daniel; 14.01.2011
comment
да, оба они обрабатывают многопоточность, проверьте комментарии к циклу с несколькими событиями. - person Javier; 14.01.2011
comment
если вы имеете в виду объяснение Стивена Гримма на домашней странице libevent, его сервер мертв :( - person Daniel; 14.01.2011
comment
многое другое можно найти в документах libev, в нем конкретно упоминается, как использовать в многопоточных приложениях, обычно используя дизайн «один цикл на поток». - person Javier; 14.01.2011
comment
libev лучше документирован, как я вижу. сделал 15к запросов с libev + multithread. Спасибо :) - person Daniel; 15.01.2011

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

Да, в настоящее время это лучший способ сделать это, и именно так это делает Nginx. Количество потоков может быть увеличено или уменьшено в зависимости от нагрузки и/или количества физических ядер на машине.

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

Второй вариант — это то, как это делает Apache2, используя пул блокирующих потоков. Здесь нет обработки событий, поэтому реализация проще, а пул означает, что потоки не создаются и не уничтожаются без необходимости, но он не может реально конкурировать с хорошо реализованным гибридом потока/асинхронности, таким как то, что вы пытаетесь реализовать, или Nginx.

На третьем месте стоит асинхронная обработка событий, такая как Lighttpd или Node.js. Ну, это второй вариант, если вы не выполняете интенсивную обработку на сервере. Но, как упоминалось ранее, один продолжительный цикл while блокирует весь сервер.

person slebetman    schedule 14.01.2011

Если у вас нет терабитного восходящего канала и вы не планируете обслуживать 10 000 одновременных подключений с одного сервера, забудьте о epoll. Это просто беспричинная непереносимость; poll или даже select тоже подойдет. Имейте в виду, что к тому времени, когда терабитные восходящие каналы и тому подобное станут стандартными, ваш сервер также будет достаточно быстрым, и вам все равно не понадобится epoll.

Если вы просто обслуживаете статический контент, забудьте о потоках и используйте системный вызов Linux sendfile. Это тоже нестандартно, но, по крайней мере, дает огромные преимущества в реальной производительности.

Также обратите внимание, что другие проектные решения (особенно чрезмерная сложность) будут гораздо больше влиять на нагрузку, которую может выдержать ваш сервер. Например, просто посмотрите, как скромный однопоточный однопроцессорный thttpd превосходит Apache и его друзей по производительности на статическом контенте — и, по моему опыту, даже на традиционном динамическом контенте cgi!

person R.. GitHub STOP HELPING ICE    schedule 14.01.2011
comment
Серверы не были значительно быстрее с 2005 года. 4 ГГц (или около того), по-видимому, является пределом. - person slebetman; 14.01.2011
comment
Я до сих пор не видел убедительного аргумента в пользу epoll, только много localhost бенчмаркинга и тому подобного. И я видел огромные причины, по которым это не нравится: всевозможные люди пишут серверы/приложения, которые используют epoll (и, следовательно, работают только в Linux), когда им нужно иметь дело только с 2-10 файловыми дескрипторами... - person R.. GitHub STOP HELPING ICE; 14.01.2011
comment
Я действительно провожу тесты на локальном хосте :), но тем не менее, я играл с libevent2, и он дал мне ~ 10k r/s и 100% загрузку ядра, поэтому я думаю, что если я добавлю потоки, он сможет работать на минимум 20-25к запросов (на 4-х ядерной машине), так что я все еще хочу поиграться с многопоточностью. - person Daniel; 14.01.2011
comment
@R.. Я думаю, что ваш комментарий действительно попал в точку, но в целом нет ничего постыдного в том, чтобы попробовать что-то новое. Использовать epoll не сложнее, чем, скажем, poll или select, и иногда вам все равно приходится учитывать ошибки, связанные с платформой (см. документацию по libev). Также не так уж сложно сгенерировать некоторые абстракции для небольших платформ для epoll, kqueue и так далее (откат к опросу, когда быстрая реализация недоступна). См., например, кодовую базу nanomsg: github.com/250bpm/nanomsg/tree/master. /src/аио - person Aktau; 28.04.2013
comment
Хотя, по правде говоря, epoll не используется для прослушивания 10 сокетов, а потому, что он также работает с timerfd и, что более важно, с eventfd. Это делает одну из самых глупых, плохо спроектированных вещей, с которыми вам приходится иметь дело в POSIX, простой, простой и управляемой. В качестве бонуса epoll немного быстрее и несколько менее неудобен, чем select, с его макросами управления fd-set и неясными ограничениями. Что, как вы сказали, может и не имеет большого значения, но и не является ошибкой. - person Damon; 06.12.2013
comment
@Damon: Все фальшивка. timerfd и eventfd одинаково хорошо работают с простым стандартным poll, но если вы их используете, вы все равно делаете что-то не так. epoll определенно намного медленнее, чем poll, если у вас есть временные файловые дескрипторы (поскольку каждое добавление/удаление является системным вызовом, а не простой записью в память). - person R.. GitHub STOP HELPING ICE; 06.12.2013
comment
Что ж, медленность — спорный вопрос, и, конечно же, это зависит от схемы использования. Epoll разработан и оптимизирован для обычного случая, когда дескриптор модифицируется редко, ждите часто. Конечно, добавлять/удалять много дескрипторов дороже (жаль, что нет системного вызова epoll_mctl). С другой стороны, это хорошо, потому что работает независимо от количества просматриваемых дескрипторов. Конечно, это не может быть O(1) в отношении событий (иногда люди ожидают этого, потому что распространенная пропаганда говорит, что epoll — это O(1)), но в этом отношении он все же превосходит select/poll. poll вернет много событий... - person Damon; 06.12.2013
comment
... очень похоже на epoll, но все же нужно передать набор дескрипторов для ожидания, а select возвращает набор fd, что как бы исключает его производительность (если только у вас нет небольшого ограничения на набор fd, например 64 на Windows, но даже с гораздо большими размерами fd-наборов, которые у вас есть, например, под Linux, вы вполне можете столкнуться с ограничением — у опросов и epoll нет искусственных ограничений, что приятно). - person Damon; 06.12.2013
comment
Пока вы не наберете хотя бы 1000 сокетов, системный вызов будет стоить больше, чем копирование списка файловых дескрипторов poll из пользовательского пространства; для select порог, вероятно, больше похож на 10000 (но, конечно, select отстой в других отношениях, и я рекомендую вообще не использовать select). Я думаю, что ваш обычный случай на самом деле является необычным случаем для большей части сетевого трафика. Распространенными случаями являются огромное количество временных подключений (HTTP) или небольшое количество постоянных подключений. epoll имеет больше смысла для чего-то вроде IRC с огромным количеством постоянных подключений, а не в обычном случае. - person R.. GitHub STOP HELPING ICE; 06.12.2013