Темы сидят без дела = плохо?
Я хочу поддерживать около 10000 одновременно работающих HTTP-клиентов на небольшом кластере компьютеров (как можно меньше). Я хотел бы поддерживать соединение с каждым клиентом, пока пользователь использует приложение, чтобы сервер мог отправлять обновления.
Я считаю, что асинхронный ввод-вывод часто рекомендуется для таких долгоживущих соединений, чтобы избежать простоя множества потоков. Но каковы проблемы с тем, что потоки бездействуют? Я считаю, что с многопоточной моделью мысленно легче работать, но я не хочу делать то, что вызовет у меня сильные головные боли. Думаю, мне придется поэкспериментировать, но мне стало интересно, знает ли кто-нибудь о каких-либо предыдущих экспериментах в этом направлении?
3 ответа
Асинхронный ввод-вывод в основном означает, что ваше приложение выполняет большую часть планирования потоков. Вместо того, чтобы позволить ОС случайным образом приостановить ваш поток и запланировать другой, у вас будет только столько потоков, сколько имеется ядер ЦП, и вы сможете выполнить другие задачи в наиболее подходящих точках - когда поток достигнет операции ввода-вывода, которая потребует некоторого времени. время.
С точки зрения производительности вышесказанное кажется очевидным преимуществом, но модель асинхронного программирования гораздо сложнее в нескольких отношениях:
- он не может быть выражен как отдельный вызов функции, поэтому рабочий процесс неочевиден, особенно когда рассматривается передача потока управления из-за исключений;
- без конкретной целевой поддержки со стороны языка программирования идиомы очень грязные: норма спагетти и / или крайне слабое отношение сигнал / шум являются нормой;
- в основном из-за вышеприведенного 1. отладка намного сложнее, так как трассировка стека не представляет прогресс в единице работы в целом;
- выполнение переходит от потока к потоку внутри пула (или даже нескольких пулов, где каждый уровень абстракции имеет свой собственный), поэтому профилирование и мониторинг с помощью обычных инструментов становятся практически бесполезными.
С другой стороны, в современных ОС произошло много благоприятных улучшений и оптимизаций, которые в основном устраняют недостатки производительности программирования синхронного ввода-вывода:
- адресное пространство огромно, поэтому пространство, отведенное для стеков, не является проблемой;
- фактическая физическая загрузка ОЗУ стеков вызовов не очень велика, поскольку только часть стека, фактически используемая потоком, выделяется в ОЗУ, а стек вызовов обычно не превышает 64 КБ;
- переключение контекста, которое раньше было чрезмерно дорогим для большего количества потоков, было улучшено до такой степени, что его издержки незначительны для всех практических целей.
Классическая статья, проходящая через многое из вышеперечисленного и некоторые другие моменты, является хорошим дополнением к тому, что я здесь говорю:
https://www.usenix.org/legacy/events/hotos03/tech/full_papers/vonbehren/vonbehren_html/index.html
В комментариях к вашему вопросу уже есть несколько хороших указателей.
Причина неиспользования потоков 10 КБ заключается в том, что это требует ресурсов памяти, а память - энергии. Модель программирования не является аргументом, поскольку поток, сидящий на клиентском соединении, не должен совпадать с тем, который хочет опубликовать событие.
Пожалуйста, обратите внимание на стандарт websockets и модель асинхронной обработки запросов в стандарте Servlet 3.0. Все недавние серверы веб-приложений java реализуют его сейчас (например, Glassfish и Tomcat), и это решение вашей проблемы.
На сам вопрос невозможно ответить, так как используемая ОС, JVM и сервер приложений отсутствуют. Тем не менее, вы можете проверить это довольно быстро, просто создав сервлет или JSP с Thread.sleep(9999999)
и делать siege -c 10000 ...
в теме.
10000 одновременных HTTP-клиентов... какие проблемы возникают при бездействии потоков?
Кажется, что стоимость свободного потока - это только память, выделенная для структуры ядра (несколько килобайт) и стека потока (512 килобайт - количество мегабайт). Но...
Очевидно, вы будете время от времени пробуждать каждую из ваших n-сотен тем, верно? И это тот момент, когда вы платите за переключение контекста, которое может быть не таким маленьким (время для вызова системного планировщика, больше кешей и т. Д.). Смотрите, например: http://www.cs.rochester.edu/u/cli/research/switch.pdf
И вам придется очень осторожно закреплять свои потоки, чтобы они не влияли на системные. В результате архитектура потоков на соединение (при блокировке ввода-вывода) может увеличить задержку системы по сравнению с асинхронным вводом-выводом. Но это все еще может работать для вашего случая, если почти все потоки припаркованы большую часть времени.
И последнее слово. Мы не знаем, сколько раз ваши потоки будут заблокированы при чтении () и сколько работы они должны сделать, чтобы обработать полученные данные. Какое оборудование, ОС и сетевые интерфейсы будут использоваться... Итак, протестируйте прототип вашей системы.