Java в 2011 году: резьбовые сокеты VS NIO: что выбрать для 64-битной ОС и последней версии Java? - PullRequest
26 голосов
/ 25 марта 2011

Я прочитал несколько постов о java.net против java.nio здесь, в StackOverflow и в некоторых блогах.Но я до сих пор не могу понять, когда следует отдавать предпочтение NIO, а не резьбовым разъемам.Можете ли вы проверить мои выводы ниже и сказать мне, какие из них являются неправильными, а какие пропущены?

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

  • В современных операционных системах и процессорах большое количество активных потоков и время переключения контекста можно считать практически несущественным для производительности

  • Общая пропускная способность NIO может быть ниже, поскольку select () и poll (), используемые асинхронными библиотеками NIO в средах с высокой нагрузкой, обходятся дороже, чем пробуждение и перевод в спящий поток.

  • NIO всегдабыл медленнее, но он позволяет обрабатывать больше одновременных соединений.По сути, это компромисс между временем и пространством: традиционный ввод-вывод быстрее, но занимает больше места в памяти, NIO медленнее, но использует меньше ресурсов.

  • В Java жесткое ограничение на число одновременных потоков15000/30000 в зависимости от JVM, и это ограничит поток для каждой модели подключения максимальным числом одновременных подключений, но JVM7 не будет иметь такого ограничения (не может подтвердить эти данные).

Итак,В заключение вы можете получить следующее:

  • Если у вас есть десятки тысяч одновременных подключений - NIO - лучший выбор, если скорость обработки запросов не является для вас ключевым фактором
  • Еслиу вас их меньше - поток на соединение - лучший выбор (учитывая, что вы можете позволить себе объем ОЗУ для максимального хранения стеков всех параллельных потоков)
  • В Java 7 вы можете захотеть перейти на NIO 2.0в любом случае.

Я прав?

Ответы [ 5 ]

3 голосов
/ 25 марта 2011

Мне это кажется правильным, за исключением части о том, что Java ограничивает количество потоков - обычно это ограничено ОС, в которой она работает (см. Сколько потоков может поддерживать Java VM? и Не удается пройти 2542 потока в Java на 4 ГБ iMac OSX 10.6.3 Snow Leopard (32 бита) ).

Чтобы достичь такого количества потоков, вам, вероятно, потребуется настроить размер стека JVM.

2 голосов
/ 20 января 2012

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

0 голосов
/ 27 января 2013

Что чаще всего упускается из виду, так это то, что NIO допускает обработку нулевого копирования.Например, если вы слушаете один и тот же многоадресный трафик из нескольких процессов, используя сокеты старой школы на одном сервере, любой многоадресный пакет копируется из буфера сети / ядра в каждое прослушивающее приложение.Таким образом, если вы создаете GRID, например, из 20 процессов, у вас возникают проблемы с пропускной способностью памяти.С помощью nio вы можете просматривать входящий буфер, не копируя его в пространство приложения.Затем процесс копирует только те части входящего трафика, которые ему интересны.

другой пример приложения: см. Пример http://www.ibm.com/developerworks/java/library/j-zerocopy/.

0 голосов
/ 11 апреля 2012

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

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

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

Таким образом, я думаю, что вам никогда не придется прибегать к выбору каналов NIO или асинхронному вводу / выводу (NIO 2) в 64-битных системах. Модель потокового соединения работает достаточно хорошо, и вы можете выполнить масштабирование до «десятков или сотен тысяч» соединений, используя более подходящую технологию низкого уровня.

Всегда полезно избегать преждевременной оптимизации (т. Е. Писать код NIO до того, как у вас появится огромное количество подключений) и не изобретать колесо (Jetty, nginx и т. Д.), Если это возможно.

0 голосов
/ 10 апреля 2012

Не существует единственного «лучшего» способа создания серверов NIO, но преобладание этого конкретного вопроса в SO предполагает, что люди думают, что это так!Ваш вопрос суммирует варианты использования, которые подходят для обоих вариантов достаточно хорошо, чтобы помочь вам принять правильное решение.

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

...