Websocket java<->java wydajność

Odpowiedz Nowy wątek
2018-09-11 14:42
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% ?

edytowany 1x, ostatnio: Szczery, 2018-09-11 14:42

Pozostało 580 znaków

2018-09-11 17:19
0

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

Pozostało 580 znaków

2018-09-11 19:02
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.


Przeważnie ignoruję niezarejestrowanych użytkowników.

Pozostało 580 znaków

2018-09-11 19:08
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

Pozostało 580 znaków

2018-09-11 19:55
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%.


Przeważnie ignoruję niezarejestrowanych użytkowników.

Pozostało 580 znaków

2018-09-11 22:21
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);
  5. 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.
  6. 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.

Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 9x, ostatnio: jarekr000000, 2018-09-11 22:29

Pozostało 580 znaków

2018-09-12 08:22
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

edytowany 1x, ostatnio: Szczery, 2018-09-12 08:25
Nadal robisz bzdury. Mierysz 3 requesty. I dokładnie te 3 wątki mają gigantyczny wpływ na twój pomiar. Żeby zobaczyć jaki sprawdź ile totalnie czasu zajęło przetworzenie tych 3 requestów (lepiej jednak 10k). I się zdziw. - jarekr000000 2018-09-12 08:53

Pozostało 580 znaków

2018-09-12 18:30
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

Jak zrobisz klienta http asynchronicznego, to też poleci szybciej. Ale chyba nie to chciałeś przetestować. - jarekczek 2018-09-12 18:32

Pozostało 580 znaków

2018-09-12 19:11
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.

Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 4x, ostatnio: jarekr000000, 2018-09-12 19:13

Pozostało 580 znaków

2018-09-12 19:45
0

1) Dodałem dodatkowo sleepa
2)
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%

edytowany 2x, ostatnio: Szczery, 2018-09-12 19:46
Czyżby wyszło, że szybsze o 30 procent? :-) - jarekr000000 2018-09-12 20:11
Dokładnie :-) - Szczery 2018-09-12 20:14

Pozostało 580 znaków

2018-09-12 20:38
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.


Przeważnie ignoruję niezarejestrowanych użytkowników.
edytowany 1x, ostatnio: jarekczek, 2018-09-12 20:39
REST był poniżej 10ms na lokalhoscie, a na dwóch maszynach oddalonych od siebie już 136. Zresztą wejście w przeglądarce na ten zasób konsola chrome pokazywała tak 140ms czyli spójnie. - Szczery 2018-09-13 08:20
Ah, te nieuważne czytanie. Nie zauważyłem, że już miałeś 2 maszyny :) Tylko że ciągle coś masz nie tak w pomiarach. Ja restem przez internet na heroku mam 158ms, a lokalnie, na raspberry pi <50ms przy drugim i kolejnych żądaniach. Więc niemożliwe, żeby 2 pecety w lokalnej sieci tak słabo ci ciągnęły. - jarekczek 2018-09-13 20:15
No właśnie te dwie maszyny nie są w sieci lokalnej :-) - Szczery 2018-09-14 08:24

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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