Programowanie reaktywne w Javie

Programowanie reaktywne 

Programowanie reaktywne jest paradygmatem programowania zajmującym się asynchronicznymi strumieniami danych i – zgodnie z nazwą – opartym na reagowaniu na zmiany w tychże – np. komponenty sieciowe reagujące na I/O, interfejsy graficzne reagujące na ruch kursorem, itp.  

W roku 2014 powstał Reactive Manifesto i do tej pory został podpisany przez ponad 24 tys. osób. Zawiera on twierdzenie, że reaktywne systemy mają 4 kluczowe cechy: są responsive, resilient, elastic oraz message-driven. Możesz sprawdzić treść manifestu aby dowiedzieć się więcej. 

 

Dlaczego potrzebujemy reaktywności w Javie?  

Java, będąc klasycznym reprezentantem stricte obiektowego podejścia do programowania przez długi czas nie prezentowała łatwego, czytelnego sposobu na uzyskanie asynchronicznego, nie blokującego przetwarzania, a kod był trudny do zrozumienia i utrzymania.  

Podejście reaktywne upraszcza uzyskanie takiego sposobu przetwarzania w “czysto” obiektowych językach – co jest szczególnie użyteczne przy przetwarzaniu bardzo dużej ilości danych czy obsłudze wielu użytkowników jednocześnie.  

Jak uzyskać reaktywność programując w Javie? 

Przed Javą 9 najpopularniejszymi implementacjami reaktywności były biblioteki stron trzecich, takich jak RxJava i Reactor. Druga biblioteka rozwijana jest na bieżąco przez twórców Springa i została włączona do Spring 5, umożliwiając m.in. łatwe tworzenie reaktywnych aplikacji z wykorzystaniem Spring Boot 2. 

Spring Boot 2 udostępnia takie moduły jak WebFlux (reaktywny odpowiednik MVC) czy reaktywne repozytoria Spring Data (dla No-SQL, ze względu na blokującą naturę JDBC). Zamiast blokującego RestTemplate do konsumpcji możemy użyć reaktywnego WebClient. 

Wydajność aplikacji reaktywnych 

Mimo, że na pierwszy rzut oka może wydawać się, że asynchroniczne przetwarzanie będzie szybsze, to nie zawsze tak jest. Podejście reaktywne i non-blocking nie sprawi, że od razu twoja aplikacja będzie działać szybciej. Może się tak stać np. wykorzystując WebClient do równoległego wykonywania zdalnych zapytań, ale w szerszym podejściu – wymaga to więcej pracy przy implementacji nie blokujących mechanizmów i może nieznacznie zwiększyć czas procesowania danych.  

Główną zaletą aplikacji reaktywnych jest natomiast zdolność do skalowania przy zachowaniu niedużej, stałej ilości dostępnych wątków i mniejszej ilości pamięci. Z drugiej strony wprowadza to nieco opóźnień chociażby przy sterowaniu wątkami.  

Mechanizmy back pressure 

Radzenie sobie z tzw. back pressure to jedna z głównych zalet filozofii programowania reaktywnego. Kiedy producent emituje dane zbyt szybko, aby konsument mógł je przetworzyć to możemy skończyć z opóźnieniamy działania systemu i zbyt wysokim zużyciem zasobów. Back pressure to inaczej zdolność konsumenta do informowania producenta danych jaką ich objętość może przeprocesować w danej chwili, aby uniknąć nadmiaru i spowolnień. Project Reactor umożliwia subskrybentom pracę w tzw. unbounded mode (push-style, pozwala na produkcję danych tak szybko na ile to możliwe) albo na użycie mechanizmów, które informują źródło danych, że odbiorca jest gotowy na przyjęcie większej ich ilości. 

Server Sent Events  

Z asynchronicznym, nie blokującym przetwarzaniem strumieni danych powiązany jest również mechanizm tzw. server sent events. Polega on na zestawieniu pojedynczego połączenia od serwera do klienta i przesyłaniu aktualizacji lub ciągłych strumieni danych.  

Jest o wiele lżejszym rozwiązaniem od ciągłego pollingu (wydajniejszym w przypadku częstych aktualizacji danych), a od websockets różni się między innymi tym, że połączenie w SSE jest jednostronne i oparte na HTTP.

Programowanie reaktywne w praktyce z użyciem Spring Boot

Na tym skończmy teoretyczny wstęp do programowania reaktywnego. Zapraszam Cię do kolejnego artykułu, który ukaże się wkrótce. Opiszę w nim praktyczne wykorzystanie mechanizmów reaktywnych w aplikacji webowej wykorzystującej Spring Boot.

Leave a Comment

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *