Подтвердить что ты не робот

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

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

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

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

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

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

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

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

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

Правильно ли я?

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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