Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Клиент/сервер под нагрузкой


Автор: pashadoro 24.4.2018, 15:47
Добрый день.

У меня не совсем обычный вопрос/консультация к экспертам.
Задание: создать ява клиент/сервер приложение, где клиент асинхронно отсылает на сервер 5 000 000 запросов, 
дожидается ответов. На этом собственно все ) (на самом деле нет, но это то, что меня особенно интересует.)

Так вот, касаемо сетАпа: у меня i5, 4Gb. Java8, Tomcat8. Запускаю клиент/сервер на одной машине.

сделал 2 варианта решения задачи.

1) В первом случае использовал Apache HttpClient, Стандартный java ExecutorService. И с 2ух потоков бомбил ендпойнт запросами.
Ситуация выглядела так. На момент, когда клиент отослал 1000 000 запросов, сервер в это время обработал около 70 000... 
Можно представить как забит был Tomcat. в итоге после 300 000 все зачахло (на сервере)

2) Далее попытался решить аналогичную проблему через WebSockets. Использовал SpringBoot.
Тут получилось так, что на кждые 10 000 запросов, Tomcat закрывал сессию, в следствии и соединение.

В обеих случаят серверная часть сделана на SpringBoot'e.

У меня не было иллюзий, что кто то начнет вместе со мной разбирать код по строке smile
Но буду весьма признателен если кто то поделиться опытом/размышлениями на данныю тему.

Возможно это вообще не http задача?
Возможно стоит полегче слать запросы (например через каждые 5к тормозить на пару секунд) - но что в итоге будет со временем на 5м?
Такие варианты как - класер итому подобное не рассматриваю. Нужно решить задачу на обычной машине.

С уважением.

Автор: LSD 24.4.2018, 17:16
Цитата(pashadoro @  24.4.2018,  16:47 Найти цитируемый пост)
Возможно это вообще не http задача?

Да. Тут на самом деле вопрос в TPS который надо выдерживать. Даже в том сетапе который есть, сервер спокойно выдержит 5 000 000 запросов, если TPS будет 1 smile

А вообще в таких задачах обычно используют неблокирующий IO, а если еще добавить реактивные стримы, то должна получится система которая выдерживает очень большое количество запросов.
На последнем JPoint как раз был доклад на эту тему: https://jpoint.ru/talks/5qmjxxmz7gkkcuc0o864gq/, так к сожалению пока есть только слайды, но зато есть ссылка на код примера: https://github.com/chbatey/akka-streams-flow-control-example

Автор: pashadoro 24.4.2018, 17:28
Цитата(LSD @  24.4.2018,  17:16 Найти цитируемый пост)
если TPS будет 1



Дружище, прошу Вас пояснить подробнее.
Как этого добиться?

Автор: AntonSaburov 24.4.2018, 18:04
Transactions per second - миллион запросов за секунду скорее всего одна машина просто не потянет. Значит надо понять, сколько запросов за одну секунду должно быть обработано.

Автор: pashadoro 24.4.2018, 18:31
Спасибо Антон.

Ребят, хочу консилиум, если Вам не сложно...
Конкретные вопросы что родились:
1) Стоит ли копать по хттп? Т.и оптимизировать Томкат итд? 
2) 1М в секунду? на хттп это нереально. Без кластеров, лодБалансеров и прочего (на моем сетапе вобщем) Меня вполне 5М за 5минут устроило бы )

В зависимости от вердикта по первому пункту, буду работать далее

Автор: LSD 24.4.2018, 18:39
Я не совсем понял, по постановке задачи есть ограничения на используемый протокол передачи, формат данных и т.д.?

Автор: pashadoro 24.4.2018, 18:50
Цитата(LSD @ 24.4.2018,  18:39)
Я не совсем понял, по постановке задачи есть ограничения на используемый протокол передачи, формат данных и т.д.?

ЛСД, в общем то нет ограничений.
Задача: асинхронно отправить с клиента на сервер 5м ордеров, сохранитьв памяти,  дожтаться подтверждения что последний сохранен(дождаться на клиенте).
После, по одному, точно так же асинхронно их закрыть. (получив ответ что последний закрыт, завершаем замер)

Нету чектких структур. 
Ордер мог бы выглядеть как: ид, сторона, объем.

Касаемо протокола - тоже нет огрничений. Но конечно же неплохо бы ограничиться хттп.

Автор: LSD 24.4.2018, 19:29
Ну тогда проще всего использовать какой-то сокетный протокол или HTTP/2.

Если сокеты и блокирующее IO: 
  •  есть пул из N потоков которые читают из N сокетов и парсят входные данные. 
  •  данные кладутся во входную очередь
  •  есть другой пул потоков которые читают данные из очереди и "сохраняют в памяти", 
  •  после сохранения кладут ack сообщение в исходящую очередь
  •  пул из N потоков читает сообщения и отправляет ack клиенту

С HTTP/2 наверное будет даже проще, там есть асинхронное АПИ, но нужна последняя версия Java.

Автор: pashadoro 24.4.2018, 20:09
Цитата(LSD @ 24.4.2018,  19:29)
Ну тогда проще всего использовать какой-то сокетный протокол или HTTP/2.

Если сокеты и блокирующее IO: 


  •  есть пул из N потоков которые читают из N сокетов и парсят входные данные. 

  •  данные кладутся во входную очередь

  •  есть другой пул потоков которые читают данные из очереди и "сохраняют в памяти", 

  •  после сохранения кладут ack сообщение в исходящую очередь

  •  пул из N потоков читает сообщения и отправляет ack клиенту


С HTTP/2 наверное будет даже проще, там есть асинхронное АПИ, но нужна последняя версия Java.

ЛСД, спасибо за ценнейшие наводки! 
На сегодня пожалуй достаточно информации.

Уже установил 10 джаву(!!!) и 9 томкат. Попробую с хттп 2 поиграть.  

Но спортивного интереса ради сделаю так же сокетное решение. По этому образцу -> 
https://medium.com/coderscorner/tale-of-client-server-and-socket-a6ef54a74763

Завтра отпишусь, доложу о прогрессе smile
Еще раз спасибо, и хорошего вечера

Добавлено через 11 минут и 24 секунды
На вскидку вопрос:
Например работаю на 10 яве с клиентом по принципу:https://labs.consol.de/development/2017/03/14/getting-started-with-java9-httpclient.html

Все четко.

Сервер крутится на 9томкате и 10 яве. ЭндПойнты на спринг буте прям из коробки будут эту чудо асинхронностьподерживать?
Либо придется сервлет писать?

Автор: LSD 25.4.2018, 11:41
Цитата(pashadoro @  24.4.2018,  21:09 Найти цитируемый пост)
Сервер крутится на 9томкате и 10 яве. ЭндПойнты на спринг буте прям из коробки будут эту чудо асинхронностьподерживать?
Либо придется сервлет писать? 

Из коробки врядли, но после настройки https://stackoverflow.com/questions/30855281/tomcat-support-for-http-2-0/37889873#37889873. Там еще есть тонкости, что браузеры поддерживают HTTP/2 только в связке с TLS, но Java HTTP/2 client по моему не требует TLS.

Цитата(LSD @  24.4.2018,  20:29 Найти цитируемый пост)
Если сокеты и блокирующее IO:

Тут еще момент, надо понять что узкое место сеть или процессор/память. Если сеть то увеличение количества одновременных соединений может помочь. Если процессор/память то лучше делать одно соединение.

Автор: pashadoro 26.4.2018, 17:51
Привет! 
Я вернулся и уделил время своей задаче smile
ЛСД, спасибо за ответ.

Да, я настроил новый сетап под хттп2. Ну очень современно все smile
Ява 10, Томкат9...
https://stackoverflow.com/questions/38612704/enable-http2-with-tomcat-in-spring-boot?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

Так настроил его под хттп2. Сервер на спрингБут заработал как есть. Были определенные нюансы, но легко решались.
Ощущение - что все это очень сыро пока что. Хотя сам АПИ шикарен. На старый смотреть не хочеться smile
Особенно на клиенте -> http://www.baeldung.com/java-9-http-client

Сухой остаток, нет. Не выполняется задача. Шлю ПУСТЫЕ гет запросы асинхронно, на эндпойнт, который возвращает "ОК".
100к и то время занимает. На миллионе модный томкат9 зачах.

(Нет, я не стал разбираться был ли РЕАЛьНО задействован хттп2, не стал копать глубоко)

Делаю вывод что на хттп, на простеньком домашнем лаптопе - подобная задача невыполнима.

Автор: AntonSaburov 27.4.2018, 10:35
А не хочется попробовать сделать совсем простые сетевые клиент и сервер - и пусть они кидают друг другу самые простые слова - Hello Server и Hello Client. Будет хотя бы информация к размышлению.

Автор: rfq 3.5.2018, 00:58
Цитата(LSD @ 24.4.2018,  18:39)
Я не совсем понял, по постановке задачи есть ограничения на используемый протокол передачи, формат данных и т.д.?

Ну так реализуйте backpressure для предотвращения перегрузки сервера. Это такое простое дополнение к протоколу запросов. Суть его в том, что прежде чем послать запрос, клиент запрашивает на это разрешение. Допустим, сервер может хранить необработанными 10000 сообщений. Надо вести учет свободного места для сообщений: пришло сообщение - уменьшаем на 1, обработано и забыто - увеличиваем. Это свободное место делится между клиентами. Клиент подключился - выдаем ему разрешение на 500 сообщений, если есть столько места. Если нет - ставим его запрос в очередь. Когда память освободится, первый запрос из очереди удовлетворяется. Когда клиент исчерпал свою квоту, он делает запрос на следующую порцию, опять запрос либо удовлетворяется, либо ставится в очередь. В общем, получается такой семафор, только распределенный.

Автор: LSD 3.5.2018, 12:33
Цитата(rfq @  3.5.2018,  01:58 Найти цитируемый пост)
Ну так реализуйте backpressure для предотвращения перегрузки сервера. Это такое простое дополнение к протоколу запросов. Суть его в том, что прежде чем послать запрос, клиент запрашивает на это разрешение. Допустим, сервер может хранить необработанными 10000 сообщений. Надо вести учет свободного места для сообщений: пришло сообщение - уменьшаем на 1, обработано и забыто - увеличиваем. Это свободное место делится между клиентами. Клиент подключился - выдаем ему разрешение на 500 сообщений, если есть столько места. Если нет - ставим его запрос в очередь. Когда память освободится, первый запрос из очереди удовлетворяется. Когда клиент исчерпал свою квоту, он делает запрос на следующую порцию, опять запрос либо удовлетворяется, либо ставится в очередь.

Это уже все есть из коробки - TCP Window, более того тот пример который я http://forum.vingrad.ru/index.php?showtopic=392913&view=findpost&p=2676088 как раз на его основе и работает. 
TCP Window лучше тем, что работает на уровне TCP стека и не требует никакой поддержки со стороны клиента, не надо ни расширять протокол, ни дорабатывать клиента.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)