Websocket java<->java wydajność

1

Witam,
ostatnio zastanawiamy się na migracją aplikacji desktopowej z http rest api na websocket aby 1 zyskać trochę na wydajności 2. komunikacja dwukierunkowa.
I teraz mam dziwny problem z wydajnością okazuje się z testów ze websockety są wolniejsze niż zwykły rest call.
U mnie:
REST

Response time 396
Response time 6
Response time 3

WebSocket

Response time 55
Response time 31
Response time 32

Przykładowy projekt w spring boot

  1. Uruchamiamy serwer klasa Application.java
  2. Klient RestClient
  3. Klient WebSocketClient
    https://github.com/MirekSz/websocket-client

Co robię źle na necie piszą, że websocket'y szybsze o 30% ?

0

A wziąłeś pod uwagę zagadnienie wysyłania/odbierania plików np. graficznych?

0

Nie sądzę, że dostaniesz zysk 30%. A czemu działa tak powoli? Nie pokazałeś metodologii pomiaru na websocket, więc trudno zgadnąć. Naturalne wydaje się mierzenie analogicznie jak http, po stronie klienta, w wywołaniach sekwencyjnych.

Po drugie mierzenie na lokalhoście też może nic nie wykazać.

Po trzecie - jak masz keep-alive, to nici z zysku na websockecie.

0

Sama metodologia na githubie. O ile w REST SYNC sprawa prosta to w websocket generujemy żądanie z aktualnym System.currentTimeMillis() odbieram w serwerze i ten long znów wysyłam do klienta (w ten sposób symuluje request-response) i liczę równicę w ms

1

Ok, racja. Nie doczytałem w kodzie tego odbioru wiadomości. Niemniej z jednym miałem słuszność: trzeba zrobić sekwencyjnie.

Response time 119
Response time 7
Response time 6

Jak to osiągnąłem? Powiedzieć wprost? :)

Ze skruchą jednak przyznaję, że czas odpowiedzi faktycznie spada o jakieś 30%.

1
  1. Zmierzyłes na trzech requestach. To raczej powinno trafić do sekcji WTF, albo perełki, Na pewno nie do pomiary.
  2. Zrób na 1000-10000 requestach, to coś możesz wnioskować.
  3. Jak już @jarekczek zauważył: w wersji ws masz wielowątkowego klienta, więc przemulasz serwer (jak na jednym kmputerze odpalasz to szczególnie) - oczywiście, że latencja wzrośnie. A w ajax jeden wątek.
  4. Możesz zrobić jeden wątek klienta WS:
ThreadPoolTaskScheduler sche = new ThreadPoolTaskScheduler();
sche.setPoolSize(1);
stompCient.setTaskScheduler(sche);
  1. Na koniec możesz użyć **CountDownLatch **, aby zmierzyć ile czasu np. zajmuje przerzucenie (synchroniczne (lub nie)) 10000 requestów przez ws - wersus Ajax.
    Bardzo biednie zrobione u mnie pomiary to: Czas 10k ws = 2222ms, czas 10k ajax 24303ms. Z tym, że też nie brał bym sobie tego pomiaru bardzo do serca... Ale widać , że skrajnie różne wyniki od twoich.
  2. Ostatnie - to de fakto mierzysz Springa + Stompa, które dają swoje narzuty - ten message Stompowy ma dodatkowe nagłówki. Więc nie mierzysz Ajax kontra WS tylko Ajax kontra Stomp over WS.
0

Dzieki za uwagi
Nawet zrobienie

ThreadPoolTaskScheduler sche = new ThreadPoolTaskScheduler();
sche.setPoolSize(1);
stompCient.setTaskScheduler(sche);

Nie poprawnia czasu jednak @jarekczek 'a sleep już tak
Nowy czasy ws

Response time 88
Response time 2
Response time 2

Co do zamulania serwera 3 wątkami to jakaś słabizna 3 wątki to mało aby czasy wzrosły z 2ms -> 31ms

0

No dobra zrobiłem pomiary na razie na localhost dla 10.000 tyś próbek i sumaryczny czas potrzebny na obsługę REST API to
24568 ms a WS to 5567ms czyli prawie 5 razy szybciej. Ale to tylko wtedy jak mam usunięty ten sleep

for (int i = 0; i < 10000; i++) {
			connect.get().send("/app/hello", new Request(System.currentTimeMillis()));
			Thread.sleep(10);
		}

Trochę nie rozumiem dlaczego. Serwer WS jest jednowątkowy czy połączenie WS nie lub atakowania z wielu wątków

1

Ładniej. Pomiar już dużo lepszy.
Ale.

  1. Musz buga. Dorzuć sleepa przed zebraniem wyniku w websocketclient. Inaczej nie mierzysz wszystkich requestów. Pomyłka jest na korzyść ws (pisałem, żeby latcha dać).

  2. Wątki. Masz klasyczny błąd . Robisz pomiary na tej samej maszynie. 10cio wątkowy klient obciąża maszynę bardziej niż jednowątkowy. Serwer to odczuwa. Możesz zrobić pomiary z innego kompa lub odpalić klienta w nice(nie wiem czy nice pomoże).

  3. Ogólnie mierzenie sumarycznej latencji jest śmierdzące. Szczególnie jak atakujesz klientem o różnej liczbie wątków.

Przykład:
Załóżmy, że masz 10 requestów do zrobienia:

  • W wersji a klient jest jednowątkowy - każdy request zajmuje 2 sekundy. Po 20-tu sekundach zrobione. Sumaryczna latencja 20 sekund.
  • w wersji b mamy klienta i serwera 10 wątkowego. Obrobienie każdego requesta niech zajmuje 10 sekund. Odpalamy 10 na raz. Po 10 sekundach wszystko jest przetworzone. Dochodzi 10 odpowiedzi. Czas połowę krótszy niż w wersji a. Ale sumaryczna latencja - 100 sekund. 5 razy tyle.
  1. Twój pomiar dodatkowo jest zafałszowany przez bogate logi, ale to drobniejszy problem.
0
  1. Dodałem dodatkowo sleepa

Dobra mam pomiary z dwóch maszyn dla 1000 requestów dłużej nie chciało mi się czekać

Sumy
REST API 136154ms
WS 95660ms

czyli średni 136ms vs 95ms czyli tak około 30%

1

Z tym "szybsze", to trzeba ostrożnie. Wyszło, że api, które nic nie robi jest szybsze o 30%. Api, które cokolwiek robi będzie miało gorszy wynik procentowy. Żeby ktoś nie pomyślał, że w magiczny sposób sobie skróci czasy odpowiedzi. Po prostu zyskać można określoną liczbę milisekund na każdym requeście, prawdopodobnie kilka. No i popraw jeszcze prosze te wyniki bo widzieliśmy wyraźnie, że rest jest poniżej 10 ms, więc nie może mieć 136.

Chętnie zobaczyłbym wyniki przeprowadzone na 2 różnych fizycznych maszynach, osobna klient, osobna serwer. Najlepiej na ethernecie 1G. Ale i tak dzięki za demonstrację, to było ciekawe.

1 użytkowników online, w tym zalogowanych: 0, gości: 1