Застереження відбору / опитування проти реакторів epoll в Twisted


95

Все, що я прочитав і пережив (додатки, засновані на Tornado), змушує мене думати, що ePoll є природною заміною мереж на основі Select та Poll, особливо з Twisted. Що робить мене параноїком, це досить рідкісне явище, коли краща техніка чи методологія не мають ціни.

Читання кількох десятків порівнянь між epoll та альтернативами показує, що epoll, безумовно, є переможцем у швидкості та масштабованості, зокрема, що масштабується лінійно, що є фантастикою. Тим не менш, як щодо використання процесора та пам'яті, чи все-таки epoll є головним?

Відповіді:


190

Для дуже невеликої кількості сокетів (звичайно, залежно від вашого обладнання, але ми говоримо про щось приблизно 10 або менше), select може перевершити еполь у використанні пам'яті та швидкості роботи. Звичайно, при такій невеликій кількості розеток обидва механізми настільки швидкі, що вас не хвилює ця різниця у переважній більшості випадків.

Однак одне уточнення. І вибір, і еполь масштабуються лінійно. Однак велика різниця полягає в тому, що API, спрямовані на користувальницький простір, мають складність, яка базується на різних речах. Вартістьselect дзвінка приблизно відповідає значенню дескриптора файлу з найбільшим номером, який ви передаєте. Якщо вибрати на одному fd, 100, то це приблизно вдвічі дорожче, ніж на одному fd, 50. Додавати більше fds нижче найвищого не зовсім безкоштовно, тому на практиці трохи складніше, ніж це, але це є гарним першим наближенням для більшості реалізацій.

Вартість epoll наближається до кількості дескрипторів файлів, які насправді мають події на них. Якщо ви відстежуєте 200 дескрипторів файлів, але лише 100 із них мають події, то ви (дуже грубо) платите лише за ці 100 активних дескрипторів файлів. Саме тут epoll має тенденцію запропонувати одну із своїх головних переваг перед відбором. Якщо у вас є тисяча клієнтів, які переважно не працюють, тоді, коли ви використовуєте select, ви все одно платите за всі тисячі з них. Однак з epoll це наче у вас лише кілька - ви платите лише за ті, що активні в будь-який момент часу.

Все це означає, що epoll призведе до меншого використання центрального процесора для більшості робочих навантажень. Що стосується використання пам'яті, це трохи підкинути. selectвдається представити всю необхідну інформацію вкрай компактно (один біт на дескриптор файлу). І обмеження FD_SETSIZE (зазвичай 1024) на те, скільки дескрипторів файлів можна використовувати (читання, запис, виняток). Порівняно з тими макс. 384 байтами, epoll - це різновид свині. Кожен дескриптор файлу представлений багатобайтовою структурою. Однак в абсолютному вираженні він все одно не буде використовувати багато пам'яті. Ви можете представити величезну кількість дескрипторів файлів кількома десятками кілобайт (я думаю, приблизно 20 тис. На 1000 дескрипторів файлів). І ви також можете взяти до уваги той факт, що вам доведеться витратити всі 384 цих байтівselect означає, що ви ніколи не витратите більше 128 байт на кожен з трьох наборів fd, з якими ви можете використовуватиselectselectякщо ви хочете відстежувати лише один дескриптор файлу, але його значення, як правило, становить 1024, тоді як з epoll ви витратите лише 20 байт. І все-таки всі ці цифри досить малі, тому це не має великої різниці.

І є ще така перевага epoll, про яку ви, мабуть, уже знаєте, що вона не обмежується дескрипторами файлів FD_SETSIZE. Ви можете використовувати його для моніторингу стільки дескрипторів файлів, скільки у вас є. І якщо у вас лише один дескриптор файлу, але його значення більше, ніж FD_SETSIZE, epoll також працює з цим, але selectні.

Випадково, я також нещодавно виявив один незначний недолік epollпорівняно з selectабо poll. Хоча жоден із цих трьох API не підтримує звичайні файли (тобто файли у файловій системі), selectі pollдемонструють цю відсутність підтримки, оскільки повідомляють такі дескриптори як завжди читабельні та завжди записні. Це робить їх непридатними для будь-якого значущого типу неблокуючої файлової системи вводу-виводу, програма, яка використовує selectабо pollвипадково зустрічає дескриптор файлу з файлової системи, принаймні продовжуватиме працювати (або якщо це не вдасться, це не буде з selectабо poll), хоча йому , можливо , не з кращого продуктивністю.

З іншого боку, epollшвидко не вдасться з помилкою ( EPERMмабуть) при запиті відстежувати такий дескриптор файлу. Власне кажучи, це навряд чи неправильно. Це просто явним чином сигналізує про відсутність підтримки. Зазвичай я аплодував би явним умовам відмови, але цей є недокументованим (наскільки я можу зрозуміти) і призводить до повністю зламаної програми, а не до програми, яка просто працює з потенційно погіршеною продуктивністю.

На практиці єдине, що я це бачив, - це взаємодія зі stdio. Користувач може перенаправити stdin або stdout з / на звичайний файл. Тоді як раніше stdin та stdout були б конвеєром - підтримуваним epoll - чудово - тоді він стає звичайним файлом, і epoll голосно виходить з ладу, порушуючи програму.


Дуже приємна відповідь. Подумайте, явно сказати про поведінку людини pollдля повноти?
кварк

6
Мої два центи на поведінку читання зі звичайних файлів: я, як правило, віддаю перевагу відмові від погіршення продуктивності. Причина полягає в тому, що це набагато більше шансів бути виявленим під час розробки і, отже, правильно обійти (скажімо, маючи альтернативний метод здійснення вводу-виводу для фактичних файлів). YMMV, звичайно: може не бути помітного уповільнення, і в цьому випадку збій не буде кращим. Але різке уповільнення, яке трапляється лише в особливих випадках, може бути дуже важко вловити під час розробки, залишаючи це як бомбу сповільненої дії, коли насправді розгорнуто.
кварк

1
Просто потрібно повністю прочитати вашу редакцію. У певному сенсі я погоджуюсь з тим, що, мабуть, не годиться, щоб epoll не імітував своїх попередників, але знову ж таки я можу уявити розробнику, який реалізував думку про помилку EPERM: "Просто тому, що вона завжди була зламана, не робить правильно зламати мою як Ну." І ще один зустрічний аргумент: я захисник-програміст, і все, що минуло 1 + 1, є підозрілим, і я кодую таким чином, щоб допустити витончені помилки. Помилка ядра через помилку, що очікується, не є приємною або уважною.
Девід

1
@ Jean-Paul, чи можете ви додати пояснення і щодо kqueue?
Хороша людина

Якщо відкинути продуктивність, чи є проблема, яка виникає внаслідок цього (від man select) Ядро Linux не накладає фіксованого обмеження, але реалізація glibc робить fd_set типом фіксованого розміру, з FD_SETSIZE визначеним як 1024, а макроси FD _ * () працюють відповідно до ця межа. Для моніторингу дескрипторів файлів, що перевищують 1023, використовуйте замість опитування (2). У CentOS 7 я вже бачив проблеми, коли мій власний код не вдався до select (), тому що ядро ​​повернуло дескриптор файлу> 1023, і я зараз розглядаю проблему, яка пахне, ніби це Twisted, потрапляючи в ту ж проблему.
Paul D Smith

4

Під час тестів у моїй компанії вийшло одне питання з epoll (), таким чином, одна вартість порівняно з select.

При спробі читати з мережі з таймаутом, створення epoll_fd (замість FD_SET) та додавання fd до epoll_fd набагато дорожче, ніж створення FD_SET (що є простим malloc).

Відповідно до попередньої відповіді, оскільки кількість FD у процесі стає великою, вартість select () стає вищою, але під час нашого тестування, навіть із значеннями fd в 10000, select все-таки був переможцем. Це випадки, коли існує лише одна fd, на яку потік очікує, і просто намагаючись подолати той факт, що мережеве читання та мережеве записування не таймаутуються при використанні моделі блокуючого потоку. Звичайно, моделі блокувальних потоків мають низьку продуктивність у порівнянні з неблокуючими реакторними системами, але бувають випадки, коли для інтеграції з певною базою застарілого коду це потрібно.

Цей варіант використання рідкісний у високоефективних додатках, оскільки модель реактора не потребує створення нового epoll_fd щоразу. Для моделі, де epoll_fd є довговічним - що, безумовно, є кращим для будь-якого високопродуктивного серверного дизайну - epoll є безперечним переможцем у всіх відношеннях.


5
Але ви навіть не можете використовувати, select()якщо у вас є значення дескриптора файлу в діапазоні 10k + - якщо ви не перекомпілюєте половину системи, щоб змінити FD_SETSIZE - тому мені цікаво, як ця стратегія взагалі працювала. Для сценарію, який ви описали, я б, мабуть, подивився, poll()який набагато більше схожий, select()ніж схожий, epoll()але видаляє обмеження FD_SETSIZE.
Жан-Поль Кальдероне,

Ви можете використовувати select (), якщо у вас є значення дескриптора файлу в діапазоні 10K, оскільки ви можете malloc () FD_SET. Насправді, оскільки FD_SETSIZE - час компіляції, а фактичний ліміт fd знаходиться під час виконання, ТІЛЬКИ безпечне використання FD_SET перевіряє номер дескриптора файлу відповідно до розміру FD_SET і робить malloc (або моральний еквівалент), якщо FD_SET є занадто малий. Я був шокований, коли побачив це у виробництві із замовником. Після програмування сокетів протягом 20 років весь код, який я коли-небудь писав - і більшість навчальних посібників в Інтернеті - небезпечний.
Брайан Булковскі

5
Наскільки мені відомо, це неправда на будь-яких популярних платформах. FD_SETSIZE- це константа часу компіляції, встановлена ​​під час компіляції вашої бібліотеки C. Якщо ви визначите його в іншому значенні під час створення своєї програми, то ваша програма та бібліотека C не погодиться, і все піде погано. Якщо у вас є посилання, які стверджують, що можна перевизначити безпечно, FD_SETSIZEмені було б цікаво їх переглянути.
Жан-Поль Кальдероне,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.