Один поток на клиента. Выполнимо? - PullRequest
19 голосов
/ 05 октября 2010

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

handshake();

while(!closed) {
  length = readHeader(); // this usually blocks a few seconds
  readMessage(length);
}

cleanup();

(потоки создаются из Executors.newCachedThreadPool(), поэтому при их запуске не должно быть значительных накладных расходов)

Я знаю, что это немного наивнои это не очень хорошо масштабируется для многих соединений, если потоки были выделенными потоками ОС.Однако я слышал, что несколько потоков в Java могут совместно использовать один аппаратный поток.Это правда?

Зная, что я буду использовать виртуальную машину Hotspot под Linux, на сервере с 8 ядрами и 12 ГБ оперативной памяти, вы думаете, эта установка будет хорошо работать для тысяч соединений?Если нет, каковы альтернативы?

Ответы [ 10 ]

5 голосов
/ 05 октября 2010

Это хорошо масштабируется до сотен соединений, а не до тысяч.Одна из проблем заключается в том, что поток Java также занимает немного стека (например, 256 КБ), и у ОС будут проблемы с планированием всех ваших потоков.

Посмотрите на Java NIO или framworks, которые помогут вам начать работусложные вещи легче (например, Apache Mina)

5 голосов
/ 05 октября 2010

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

Распространенной альтернативой является использование селекторов и неблокирующих операций ввода-вывода, найденных в пакете java.nio.

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

3 голосов
/ 05 октября 2010

JVM для Linux использует сопоставление потоков один к одному. Это означает, что каждый поток Java отображается в один собственный поток ОС.

Таким образом, создание тысячи или более потоков не является хорошей идеей, поскольку это повлияет на вашу производительность ( переключение контекста , кэш сбрасывает / пропускает , синхронизация задержка и т. Д.). Это также не имеет никакого смысла, если у вас менее тысячи процессоров.

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

Смотри также:

3 голосов
/ 05 октября 2010

Чтобы иметь хорошую производительность при работе со многими сокетами, вы обычно используете подход select, который заключается в том, как Unix API обрабатывает однопоточные приложения с несколькими сокетами, которым требуется много ресурсов.java.nio пакет, который имеет класс Selector, который в основном способен проходить через все открытые сокеты и уведомлять вас о появлении новых данных.

Вы регистрируете все открытые потоки внутри одного Selector итогда вы можете обрабатывать их все из одного потока.

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

2 голосов
/ 06 октября 2010

Попробуйте Netty .

модель "один поток на запрос" - это способ написания большинства серверов приложений Java.Ваша реализация может масштабироваться так же хорошо, как и они.

1 голос
/ 06 октября 2010

Я бы предположил, что это зависит больше от того, что еще сервер делает, когда обрабатывает сообщения. Если он относительно легкий, то спецификации вашей машины ЛЕГКО справятся с простой обработкой соединений тысяч таких процессов. Десятки тысяч - это, пожалуй, еще один вопрос, но вам нужно только две машины в одной сети, чтобы на самом деле эмпирически проверить и получить определенный ответ.

1 голос
/ 05 октября 2010

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

ОБНОВЛЕНИЕ : В этом сообщении от Мэтью Шмидта утверждается, что соединитель на основе NIO (написанный Филипом Хаником) в Tomcat 6 достиг 16 000 одновременных соединений.

Если вы хотите написать свой собственный соединитель, взгляните на MINA , чтобы помочь с абстракциями NIO. У MINA также есть функции управления, которые могут устранить необходимость в другом контейнере (если вы беспокоитесь о развертывании многих устройств и их работе и т. Д.)

1 голос
/ 05 октября 2010

Потоки не так дороги, как раньше, поэтому «обычная» реализация ввода-вывода может быть вполне приемлемой. Однако, если вы смотрите на масштабирование до тысяч или даже больше, вероятно, стоит изучить что-то более сложное.

Пакет java.nio решает эту проблему, обеспечивая мультиплексирование / неблокирование ввода-вывода сокетов, что позволяет связывать несколько соединений с одним селектором. Однако из-за многопоточности и неблокирования это решение гораздо сложнее сделать правильно, чем простой подход с блокировкой.

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

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

Зачем кататься самостоятельно? Вы можете использовать контейнер сервлетов с сервлетами, очередью сообщений или ZeroMQ.

0 голосов
/ 06 октября 2010

Я думаю, что лучший подход - не обрабатывать потоки самостоятельно.Создайте пул (ThreadExecutor или другой материал) и просто отправьте работу в ваш пул.

Конечно, я думаю, что асинхронный ввод-вывод сделает это лучше и быстрее, но поможет вам с проблемами сокетов и сетей.Только.Когда ваши потоки блокируются из-за ввода / вывода, JVM переводит его в спящий режим и переключается на другой поток до тех пор, пока блокирующий ввод / вывод не вернется.Но это заблокирует только поток.Ваш процессор продолжит работать и начнет обрабатывать другой поток.Таким образом, минус время на создание потока, то, как вы используете ввод / вывод, не сильно влияет на вашу модель.Если вы не создаете потоки (используя пул), ваша проблема решена.

...