Многие блокирующие VS одиночные неблокирующие работники

9

Предположим, что есть HTTP-сервер, который принимает соединения, а затем он каким-то образом ожидает полной отправки заголовков. Интересно, каков наиболее распространенный способ его реализации и каковы остальные плюсы и минусы. Я могу думать только об этом:

Многие блокирующие работники хороши тем, что:

  • Это более отзывчиво.
  • Проще вводить новые соединения (работники выбирают их сами, а не посторонние, ожидая, пока он не сможет добавить их в синхронизированный список).
  • Загрузка ЦП автоматически балансируется (без каких-либо дополнительных усилий) по мере увеличения и уменьшения количества соединений.
  • Меньшее использование процессора (заблокированные потоки выводятся из цикла выполнения и не требуют никакой логики для перехода между клиентами).

Одиночный неблокирующий работник хорош, потому что:

  • Использует меньше памяти.
  • Менее уязвимы для ленивых клиентов (которые подключаются к серверу и отправляют заголовки медленно или вообще не отправляют).

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

Редактирование (дополнительные исследования): Некоторый ресурс, который я нашел в Интернете (« Тысячи потоков и блокирующий ввод-вывод - старый способ написания Java-серверов снова новый (и намного лучше) » Пола Тима), намекает на то, что блокирующий подход, как правило, лучше, но Я до сих пор не знаю, как бороться с поддельными связями.

PS Не предлагайте использовать какую-либо библиотеку или приложения для этой задачи. Меня больше интересует знание того, как это на самом деле работает или может работать, чем работать.

PSS Я разделил логику на несколько частей, и эта обрабатывает только прием заголовков HTTP. Не обрабатывает их.

Pijusn
источник
Вот, много лет назад я написал многопоточный сервер с блокирующим вводом / выводом, потому что его было легко написать. Коллега написал другой вид, и это сработало превосходно. Это были две формы основного предложения продукции в компании, в которой я работал. Для «ленивых клиентов» в сценарии блокировки вы можете установить тайм-аут на получение данных.

Ответы:

4

Там нет серебряной пули

На практике это зависит ...

tl; dr - простое решение, используйте nginx ...

Блокировка:

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

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

AFAIK, использование многопроцессного подхода на блокирующем HTTP-сервере, как правило, предпочтительнее, поскольку безопаснее / проще управлять / восстанавливать память безопасным способом. Сборка мусора становится не проблема, когда восстановление памяти так же просто, как остановка процесса. Для длительных процессов (например, демона) эта характеристика особенно важна.

Хотя издержки переключения контекста могут показаться незначительными при небольшом количестве работников, недостатки становятся более значимыми, поскольку нагрузка масштабируется до сотен или тысяч одновременных соединений. В лучшем случае переключение контекста масштабирует O (n) до числа присутствующих работников, но на практике это, скорее всего, хуже.

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

Неблокируемому:

Неблокирующим будет что-то вроде Node.js или nginx. Они особенно известны благодаря масштабированию до гораздо большего числа соединений на узел под интенсивной нагрузкой ввода-вывода. По сути, как только люди достигли верхнего предела того, что могут обрабатывать серверы на основе потоков / процессов, они начали изучать альтернативные варианты. Это также известно как проблема C10K (то есть способность обрабатывать 10 000 одновременных подключений).

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

Хотя это может не работать для многих сетевых протоколов, природа HTTP без сохранения состояния особенно хорошо работает для неблокирующих архитектур. Используя комбинацию обратного прокси-сервера и нескольких неблокирующих HTTP-серверов, можно идентифицировать и обойти узлы, испытывающие большую нагрузку.

Даже на сервере, который имеет только один узел, для установки очень распространено включать один сервер на ядро ​​процессора, чтобы максимизировать пропускную способность.

Обе:

«Идеальный» вариант использования был бы комбинацией обоих. Обратный прокси-сервер спереди, предназначенный для запросов маршрутизации сверху, затем смесь блокирующих и неблокирующих серверов. Неблокирующая для задач ввода-вывода, таких как обслуживание статического содержимого, содержимого кэша, HTML-содержимого. Блокировка для задач с высокой нагрузкой на процессор, таких как кодирование изображений / видео, потоковое содержимое, перехват чисел, запись в базу данных и т. Д.

В твоем случае:

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

Я бы посоветовал проверить документацию для встроенного обратного прокси-сервера nginx .

В стороне:

Я прочитал рецензию по предоставленной вами ссылке, и есть смысл, что async был плохим выбором для их конкретной реализации. Вопрос может быть обобщен в одном заявлении.

Установлено, что при переключении между клиентами код для сохранения и восстановления значений / состояния оказался сложным

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

Похоже, они плохо разбирались в асинхронности и в результате сделали много плохих предположений.

Эван Плейс
источник