Поток Java для модели соединения против NIO - PullRequest
37 голосов
/ 20 января 2011

Является ли неблокирующая Java NIO все еще медленнее, чем ваш стандартный поток на асинхронный сокет подключения?

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

Я пишу MMORPG-сервер на Java, который должен легко масштабировать 10000 клиентов при достаточно мощном оборудовании, хотя максимальное количество клиентов составляет 24000 (что, я считаю, невозможно достичь для потока на модель соединения из-за ограничение потока 15000 в Java). Из трехлетней статьи я слышал, что блокировка ввода-вывода с помощью потока для каждой модели подключения все еще была на 25% быстрее, чем NIO (а именно, этот документ http://www.mailinator.com/tymaPaulMultithreaded.pdf),, но можно ли добиться того же в этот день? Java С тех пор многое изменилось, и я слышал, что результаты были сомнительными при сравнении реальных сценариев, поскольку используемая виртуальная машина не была Sun Java. Кроме того, поскольку это сервер MMORPG, в котором много одновременно работающих пользователей взаимодействуют друг с другом, использование методов синхронизации и безопасности потоков снизит производительность до такой степени, что однопоточный селектор NIO, обслуживающий 10000 клиентов, будет быстрее? (вся работа не обязательно должна обрабатываться в потоке с помощью селектора, она может обрабатываться в рабочих потоках, например, как работает MINA / Netty).

Спасибо!

Ответы [ 7 ]

21 голосов
/ 21 января 2011

Преимущества NIO следует принимать с зерном соли.

На HTTP-сервере большинство подключений являются поддерживающими соединения, в большинстве случаев они простаивают.Было бы напрасной тратой ресурсов предварительно выделить поток для каждого.

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

Если вы используете NIO, вам придется постоянно перераспределять поток для соединения.Это может быть худшее решение по сравнению с простым решением с фиксированным потоком на соединение.

Размер стека потока по умолчанию довольно велик (1/4 МБ?), Это главная причина, почемуограниченные темы.Попробуйте уменьшить его и посмотреть, может ли ваша система поддерживать больше.

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

12 голосов
/ 21 января 2011

На самом деле существует 3 решения:

  1. Несколько потоков
  2. Один поток и NIO
  3. Оба решения 1 и 2 одновременно

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


Использование NIOс одним потоком плохая идея по нескольким причинам:

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

Один поток на соединение - плохая идея, потому что он не масштабируется.Допустим, есть:

  • 10 000 соединений
  • 2 ЦП с 2 ядрами в каждом
  • только 100 потоков будут блокироваться в любой момент времени

Тогда вы можете понять, что вам нужно всего лишь 104 потока.Больше и вы тратите ресурсы на управление лишними потоками, которые вам не нужны.Под капотом много бухгалтерии, необходимой для управления 10 000 потоков.Это замедлит вас.


Вот почему вы объединяете два решения.Также убедитесь, что ваша виртуальная машина использует самые быстрые системные вызовы.Каждая ОС имеет свои уникальные системные вызовы для высокопроизводительного сетевого ввода-вывода.Убедитесь, что ваша виртуальная машина использует новейшие и лучшие.Я считаю, что в Linux это epoll ().

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

Это зависит от того, сколько времени вы хотите потратить на оптимизацию.Самым быстрым решением является создание ресурсов, таких как потоки и строки, когда это необходимо.Тогда пусть сборщик мусора заберет их, когда вы закончите с ними.Вы можете получить повышение производительности, имея пул ресурсов.Вместо создания нового объекта вы запрашиваете пул и возвращаете его в пул, когда закончите.Это добавляет сложность управления параллелизмом.Это может быть дополнительно оптимизировано с помощью усовершенствованных алгоритмов параллелизма, таких как неблокирующие алгоритмы .В новых версиях Java API есть несколько из них для вас.Вы можете потратить всю оставшуюся жизнь, выполняя эти оптимизации только для одной программы.Что является лучшим решением для вашего конкретного приложения, вероятно, это вопрос, который заслуживает отдельного сообщения.

9 голосов
/ 20 января 2011

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

Распространенным заблуждением является то, что NIO позволяет неблокировать IO, поэтому это единственная модель, достойная сравнения.Если вы тестируете блокировку NIO, вы можете получить его на 30% быстрее, чем старый IO.т. е. если вы используете ту же модель многопоточности и сравниваете только модели ввода-вывода.

Для сложной игры у вас гораздо больше шансов исчерпать процессор до того, как вы подключитесь к соединениям 10K.Опять же, проще иметь решение, которое масштабируется горизонтально.Тогда вам не нужно беспокоиться о том, сколько соединений вы можете получить.

Сколько пользователей могут разумно взаимодействовать?24?в этом случае у вас есть 1000 независимых групп, взаимодействующих.У вас не будет столько ядер на одном сервере.

Сколько денег на пользователей вы собираетесь потратить на сервер (ы)?Вы можете купить 12-ядерный сервер с 64 ГБ памяти менее чем за 5000 фунтов стерлингов.Если вы разместите 2500 пользователей на этом сервере, вы потратите 2 фунта за пользователя.

РЕДАКТИРОВАТЬ: У меня есть ссылка http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html, которая моя.;) Я рассмотрел это кем-то, кто является ГУРУ Java Networking, и он в целом согласился с тем, что он нашел.

3 голосов
/ 08 июня 2016

Если у вас занятые соединения, что означает, что они постоянно отправляют вам данные, а вы отправляете их обратно, вы можете использовать non-Blocking IO в сочетании с Akka.

Akka - это набор инструментов с открытым исходным кодом и среда выполнения, упрощающая создание параллельных и распределенных приложений на JVM. Akka поддерживает несколько моделей программирования для параллелизма, но подчеркивает параллелизм на основе акторов, вдохновленный Эрлангом. Языковые привязки существуют как для Java, так и для Scala.

Логика Akka неблокируемая, поэтому она идеально подходит для асинхронного программирования. Используя Akka Actors, вы можете удалить Thread overhead.

Но если ваши потоки сокетов блокируются чаще, я предлагаю использовать Blocking IO в сочетании с Quasar

Quasar - это библиотека с открытым исходным кодом для простого и легкого параллелизма JVM, которая реализует истинные легкие потоки (волокна AKA) в JVM. Волокна Quasar ведут себя так же, как обычные потоки Java, за исключением того, что у них практически нет затрат памяти и переключения задач, поэтому вы можете легко создавать сотни тысяч волокон или даже миллионы в одной JVM. Quasar также предоставляет каналы для межволоконной связи, смоделированные по аналогии с языками Go, в комплекте с переключателями каналов. Он также содержит полную реализацию актерской модели, по образцу Эрланга.

Логика Квазара блокирует, так что вы можете порождать, скажем, 24000 волокон, ожидающих на разных соединениях. Одним из положительных моментов, касающихся Quasar, является то, что волокна могут очень легко взаимодействовать с простыми нитями. Также Quasar имеет интеграцию с популярными библиотеками, такими как Apache HTTP client или JDBC или Jersey и т. Д., Поэтому вы можете использовать преимущества использования Fibers во многих аспектах вашего проекта.
Вы можете увидеть хорошее сравнение между этими двумя фреймворками здесь .

1 голос
/ 21 января 2011

Поскольку большинство из вас, ребята, говорят, что сервер должен быть заблокирован при использовании ЦП до того, как будет достигнуто 10k одновременных пользователей, я полагаю, что лучше для меня использовать подход потокового блокирующего (N) ввода-вывода, учитывая тот факт, что для этой конкретной MMORPG получение нескольких пакетов в секунду для каждого игрока не является редкостью и может привести к зависанию селектора, если один из них будет использоваться.

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

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

РЕДАКТИРОВАТЬ: Я наконец выбрал свой курс действий. На самом деле я был нерешителен и решил использовать JBoss Netty и позволить пользователю переключаться между oio или nio, используя классы

org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;

Довольно приятно, что Netty поддерживает оба!

1 голос
/ 21 января 2011

Вы можете черпать вдохновение из проекта, ранее спонсируемого Sun, который теперь называется Red Dwarf.Старый сайт на http://www.reddwarfserver.org/ не работает.
Github на помощь: https://github.com/reddwarf-nextgen/reddwarf

0 голосов
/ 28 мая 2019

Если вы выполняете сетевые вызовы на стороне клиента, скорее всего, вам просто нужен простой сокет io.

Если вы создаете технологии на стороне сервера, то NIO поможет вам отделить часть io сети от выполнения / обработки,Потоки ввода-вывода настроены как 1 или 2 для сетевого ввода-вывода.Рабочие потоки предназначены для фактической обрабатывающей части (которая варьируется от 1 до N, в зависимости от возможностей машины).

...