Java REST jako Kafka Producer

Odpowiedz Nowy wątek
2019-10-09 15:16
0

Cześć,
dostałem zadanie, które polega na wysyłaniu wiadomości z web serwisu do topicu w kafce (jestem juniorem, o ile w ogóle).
Udało się wyklikać podstawową funkcjonalność - działa. W topicu pojawia się wiadomość.
Problem w tym, że zanim dostanę responsa mijają 2 sekundy.
Pierwsza myśl - spoko, trzeba poprawić performence. Tylko jak?
Dlatego przychodzę z prośbą o pomoc, ponieważ nie wiem nawet z jakiej strony ugryźć temat.
Moje pytania / wątpliwości:

  • Chyba nie powinienem otwierać i zamykać producera w jednej funkcji
  • Kombinowałem ze statycznymi metodami w klasie "SimpleProducer", które odpowiednio utworzą lub zwrócą istniejącą instancję Producera, ale to raczej nie wpłynęło na wydajność.
  • Proszę o wskazówki jak poradzić sobie z designem takiego resta.
    Używam Jersey'a, a moim kontenerem apki jest OpenLiberty. Poniżej zamieszczam fragment kodu.

Funkcja przyjmuje POST'em skromnego json'a, zmienia go na stringa i wpisuje do topica.

@POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Model getInfo(Model model) throws JsonProcessingException {

        if(producer == null)
            producer = (KafkaProducer<String, String>) KafkaProducerExample.createProducer();
        else
            producer = (KafkaProducer<String, String>) KafkaProducerExample.getProducer();

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        String json = mapper.writeValueAsString(model);

        ProducerRecord<String, String> record = new ProducerRecord<String, String>("topic", json);

        // send message - asynchronous
        producer.send(record);

        // message produced and pushed to send method
        producer.flush();

        // close producer
        producer.close();

        return "OK";
    }
edytowany 2x, ostatnio: esy_floresy, 2019-10-09 15:17

Pozostało 580 znaków

2019-10-09 15:27
0

Jak szybko powinno się przetwarzać i co konkretnie przetwarzać, żeby było "dobrze" ?

Piszesz, "Problem w tym, że zanim dostanę responsa mijają 2 sekundy." response skąd?

1) Client --> REST ---> Kafka , klient czeka 2 sekundy na zakończenie wywołania RESTa ?

czy

2) Po drugiej stronie coś bierze komunikat z Kafki i po 2 sekundach przesyła Ci odpowiedź?

Pozostało 580 znaków

2019-10-09 15:29
0

Po 2 sekundach dostaję "OK" w postmanie i po takim czasie pojawia się komunikat w Kafce.
Wydaje mi się, że publikowanie do Kafki powinno być w granicach 50ms.

edytowany 1x, ostatnio: esy_floresy, 2019-10-09 15:32

Pozostało 580 znaków

2019-10-09 15:33
0
esy_floresy napisał(a):

Po 2 sekundach dostaję "OK" w postmanie i po takim czasie pojawia się komunikat w Kafce.

Rozbij ten czas na mniejsze bloki i zobacz, która część jest najdłuższa i tę optymalizuj. Czy może już to zrobiłeś i doszedłeś do wniosku, że to nie sieć i nie czekanie na cpu i nie coś innego ?

Która z operacji zajmuje najwięcej czasu?

Pozostało 580 znaków

2019-10-09 15:49
0

Czeli tę jedną funkcję rozbić na kilka mniejszych?
Czy użyć jakiegoś narzędzia do testowania? Jeśli tak to czy polecasz jakieś?

Tak na chłopski rozum wydaje mi się, że to jest problem z otwieraniem i zamykaniem producera z każdym requestem. Stąd pomysł na statycznego producera, bo przecież on nie zmienia swoich propertisów. Ale to nie za bardzo pomogło.
Zakładam też, że istnieją "dobre praktyki" w takich sytuacjach, których pewnie nie stosuję i chciałem o nie zapytać.

Wątpię też, że to problem samego parsowania jsona do stringa.

Tworzenie ObjectMappera w każdym wywołaniu też na pewno nie pomaga - na mojej maszynie takie tworzenie ObjectMapera zajmuje 100-200 ms. :) - catom 2019-10-09 16:03

Pozostało 580 znaków

2019-10-09 15:54
0
esy_floresy napisał(a):

Czeli tę jedną funkcję rozbić na kilka mniejszych?

Samo rozbicie nic Ci nie da, bo potrzebujesz zmierzyć ile czasu idzie na wykonanie poszczególnych operacji.

Czy użyć jakiegoś narzędzia do testowania? Jeśli tak to czy polecasz jakieś?

Masz tak prosty kod, że możesz wypluwać timestamp z dokładnością do milisekund przed wejściem do metody, po wyjściu i przed wywołaniem każdej instrukcji z tej metody.
Zwykłe System.out.println bieżącego czasu na konsolę :-)

Co o narzędzi, to możesz rozpoznać temat "java profilers".

Obstawiam, że flush() blokuje.

Pozostało 580 znaków

2019-10-09 16:04
0
esy_floresy napisał(a):

Cześć,
dostałem zadanie, które polega na wysyłaniu wiadomości z web serwisu do topicu w kafce (jestem juniorem, o ile w ogóle).
Udało się wyklikać podstawową funkcjonalność - działa. W topicu pojawia się wiadomość.
Problem w tym, że zanim dostanę responsa mijają 2 sekundy.
Pierwsza myśl - spoko, trzeba poprawić performence. Tylko jak?

Kafka ma dobry performence. To o czym mówisz to słabe latency.
Kafka jest zaprojektowana tak, żeby mieć dobry performence kosztem złego latency.


Pozostało 580 znaków

2019-10-09 16:37
3

Nie no przecież to co tam masz to dramat :) Masz tu niejako stateless service restowy, ale nie wiedzieć czemu przy każdym requeście robisz:

  • tworzenie object mappera
  • otwieranie producera do kafki
  • zamykanie producera

To wszystko jest 100 razy cięższe niż to co masz faktycznie zrobić, czyli przygotować payload dla kafki i wysłac! Czemu object mapper i producer dla kafki nie są elementami jakiegoś singletonowego serwisu którego cykl życia jest taki sam jak cykl życia aplikacji?


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
Plus konfiguracja ACK na topicu, ale to i tak nie ten rząd wielkości :D - Charles_Ray 2019-10-09 16:44

Pozostało 580 znaków

2019-10-09 16:45
0

Będzie wolno i już chyba wiem czemu ;-)

Wątek obsługujący żądanie do REST:

    producer.send(request.data); // send async - powinno być szybko
    producer.flush();              // czekamy na wysyłkę do kafi, więc dupa z asynchroniczności 

Żeby to było szybkie, to flush powinien być wykonywany per ileś tam requestów.

Możesz zwracać OK po producer.send(), a flusha robić w innym wątku, ale... istnieje ryzyko utraty zbuforowanych komunikatów.

Jak to ma być szybkie i niezawodne, to potrzebujesz zrobić własny protokół (nie w sensie technicznym, a logicznym) między klientem a Twoim systemem.

Client: Send REQ (leci REST Request, wrzucasz do kafki asynchronicznie, zwracasz OK, gdzieś tam osobno robisz flusha na producencie)
Server: REQ.ACK (jak się uda wysłać komunikat do kafi, to leci ACK)
Server: RES (jak uda się przetworzyć wiadomość to leci response do klienta jakimś innym kanałem)
Client: RES.ACK (klient wysyła potwierdzenie otrzymania wiadomości do serwera)

Możesz sobie taki protokół dowolnie rozbudowywać...

Pozostało 580 znaków

2019-10-09 16:54
0

Zgodnie z sugestiami wyrzuciłem tworzenie obiektów producera i objectmappera do singletonów.
Wyrzuciłem też z kodu flusha - i to znacznie przyspieszyło. Prawdę mówiąc chyba źle skumałem tę funkcję (flush), bo myślałem, że bez niej wiadomości nie trafią do kafki.
Dzięki za słowa krytyki, teraz przynajmniej mogę zawęzić dalszy research.

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