Mikrousługi: protokoły i narzędzia komunikacji
Mikrousługi wymieniają wiadomości w dwóch modelach: synchronicznym poprzez bezpośrednie żądania HTTP do metod innego serwisu oraz asynchronicznym za pośrednictwem brokerów takich jak Kafka czy RabbitMQ. W modelu synchronicznym nadawca oczekuje odpowiedzi, znając URL i endpointy odbiorcy. Asynchroniczny korzysta z tematów do przechowywania wiadomości bez bezpośredniego kontaktu.
Model synchroniczny sprawdza się w scenariuszach zapytanie-odpowiedź, asynchroniczny — w zdarzeniach, gdzie pewność dostarczenia jest ważniejsza od szybkości.
Synchroniczni klienci HTTP
Do bezpośrednich wywołań używa się kilku narzędzi:
- RestTemplate: blokujący klient, prosty, ale przestarzały w nowych projektach ze względu na blokowanie wątków.
- WebClient: reaktywny oparty na Project Reactor, nieblokujący, idealny do systemów o wysokim obciążeniu z asynchronicznym przetwarzaniem.
- Feign Client: deklaratywny, interfejs z adnotacjami generuje implementację klienta HTTP w Spring. Synchroniczny, z obsługą cache'owania, minimalizuje kod boilerplate.
Feign upraszcza kod: definiujesz interfejs z @GetMapping, @PostMapping — klient gotowy. WebClient wygrywa pod względem przepustowości dzięki non-blocking I/O.
Programowanie reaktywne w WebClient
Reaktywność w Project Reactor korzysta z Mono (jedna wartość) i Flux (strumień wartości). Główne różnice od zwykłej asynchroniczności:
- Przetwarzanie strumieni danych w czasie z backpressure: odbiorca sygnalizuje nadawcy gotowość.
- Deklaratywne operatory: map, filter, flatMap, buffer do transformacji.
- Leniwa ewaluacja: operacje uruchamiają się dopiero przy subskrypcji.
Przykład przetwarzania użytkowników z repozytorium:
Flux<User> users = userRepository.findAll();
Flux<String> names = users
.filter(u -> u.getAge() > 18)
.map(User::getName)
.take(10);
names.subscribe(name -> {
System.out.println("Otrzymano imię: " + name);
});
Tutaj zapytania do bazy uruchamiają się dopiero na .subscribe(). Reactor integruje się ze Spring WebFlux do reaktywnych aplikacji webowych. Stosuj przy wysokich obciążeniach lub przetwarzaniu strumieniowym, do CRUD wystarczy synchroniczne narzędzie.
WebSocket do wymiany zdarzeń
WebSocket nawiązuje stałe połączenie do dwukierunkowej wymiany zdarzeń bez powtarzanych żądań. Brak cyklu request-response: serwisy wysyłają wiadomości do otwartego kanału.
Nadaje się do:
- Czatów i powiadomień w czasie rzeczywistym.
- Gier i notowań giełdowych z natychmiastowymi aktualizacjami.
- Strumieni szeregów czasowych bez pollingu.
Wada: brak gwarancji dostarczenia przy zerwaniu połączenia. Nacisk na szybkość, nie na niezawodność.
Kafka: asynchroniczny broker wiadomości
Kafka to rozproszony system do przechowywania i dystrybucji zdarzeń. Producer wysyła do tematu (partycjonowany log), Consumer czyta z partycji.
Gwarancje dostarczenia:
- At-least-once: wiadomość dostarczona co najmniej raz (duplikaty możliwe przy awarii commita).
- Exactly-once: poprzez idempotentne producery i transakcje.
Idempotentność zapewnia ten sam rezultat dla powtarzanych żądań. Replikacja na brokerach zapobiega stratom. Kolejność zachowana w partycji według klucza (np. ID użytkownika).
Grupy consumerów rozkładają obciążenie: wielu konsumentów równolegle przetwarza partycje.
Scenariusze Kafki:
- Asynchroniczne zdarzenia: e-maile, analityka, bonusy.
- Ponowne odczytywanie historii do przeliczeń.
- Strumieniowanie (Kafka Streams, CDC z bazy).
Wady: skomplikowana konfiguracja klastra (KRaft zamiast ZooKeeper upraszcza), opóźnienie wyższe niż HTTP.
Co najważniejsze
- Wybieraj Feign do prostych synchronicznych wywołań z minimalnym kodem.
- WebClient niezbędny w reaktywnych systemach o wysokim obciążeniu z Flux/Mono.
- WebSocket do real-time dwukierunkowego bez gwarancji dostarczenia.
- Kafka do niezawodnej asynchronicznej komunikacji sterowanej zdarzeniami z historią.
- Łącz: synchroniczne do CRUD, asynchroniczne do zdarzeń.
— Editorial Team
Brak komentarzy.