Apache Ignite Zero Deployment: co to dokładnie oznacza Zero?

Apache Ignite Zero Deployment: co to dokładnie oznacza Zero?

Jesteśmy działem rozwoju technologii w sieci detalicznej. Pewnego razu kierownictwo postawiło przed nami zadanie przyspieszenia obsługi obliczeń masowych poprzez wykorzystanie Apache Ignite w połączeniu z MSSQL, pokazując stronę z doskonałymi ilustracjami i przykładami kodu w Javie. Strona od razu przypadła mi do gustu Zero Deployment, którego opis obiecuje cuda: nie musisz ręcznie wdrażać swojego kodu w Javie lub Scali na każdym węźle w siatce i ponownie wdrażać go za każdym razem, gdy się zmienia. W trakcie pracy okazało się, że Zero Deployment ma swoje specyfikacje użycia, którymi chciałbym się podzielić. Poniżej przemyślenia i szczegóły realizacji.

1. Postawienie zadania

Sedno zadania jest następujące. Istnieje słownik punktów sprzedaży SalesPoint oraz słownik produktów Sku (Stock Keeping Unit). Punkt sprzedaży ma atrybut „typSklepu” z wartościami „mały” i „duży”. Każdy punkt sprzedaży ma przypisany (ładowany z SGBD) asortyment (listę produktów punktu sprzedaży) i przekazywane są informacje o tym, że od podanej daty dany produkt
jest wyłączany z asortymentu lub dodawany do asortymentu.

Wymagana jest organizacja partycjonowanej pamięci podręcznej punktów sprzedaży oraz przechowywanie w niej informacji o podłączonych produktach na miesiąc naprzód. Zgodność z systemem produkcyjnym wymaga od węzła klienta Ignite załadowania danych, obliczenia agregatu typu (typSklepu, kodProduktu, dzień, liczba_punktów_sprzedaży) i wyeksportowania go z powrotem do SGBD.

2. Badanie literatury

Nie mam jeszcze doświadczenia, więc zaczynam od podstaw. To znaczy od przeglądu publikacji.

Artykuł z 2016 roku Poznajemy Apache Ignite: pierwsze kroki zawiera link do dokumentacji projektu Apache Ignite oraz krytykę niejasności tej dokumentacji. Przeczytałem kilka razy, a zrozumienia nie ma. Zwracam się do oficjalnego samouczka getting-started, który
optymistycznie obiecuje „Wkrótce wszystko będzie działało!”. Zajmuję się ustawieniami zmiennych środowiskowych, oglądam dwa filmy Apache Ignite Essentials, które okazały się dość mało przydatne dla moim konkretnym zadaniu. Udało mi się uruchomić Ignite z wiersza poleceń ze standardowym plikiem „example-ignite.xml”, buduję pierwszą aplikację Compute Application z wykorzystaniem Maven. Aplikacja działa i korzysta z Zero Deployment, jaka piękność!

Czytam dalej, a tam przykład od razu używa affinityKey (utworzonego wcześniej za pomocą zapytania SQL), a do tego zastosowano tajemniczy BinaryObject:

IgniteCache<BinaryObject, BinaryObject> people 
        = ignite.cache("Person").withKeepBinary(); 

Przeczytałem trochę: format binarny — coś w rodzaju refleksji, dostęp do pól obiektu po nazwie. Może odczytać wartość pola bez pełnej deserializacji obiektu (oszczędność pamięci). Ale czemu zamiast Person używa się BinaryObject, skoro jest Zero Deployment? Czemu IgniteCache<Key,Person> tłumaczy się na IgniteCache<BinaryObject, BinaryObject>? Na razie niejasne.

Przerabiam aplikację Compute Application na swój przypadek. Klucz główny w tabeli punktów sprzedaży w MSSQL zdefiniowany jako [id] [int] NOT NULL, tworzę cache analogicznie.

IgniteCache<Integer, SalesPoint> salesPointCache=ignite.cache("spCache")

W pliku xml-konfiguracyjnym podaję, że cache jest partycjonowany.

<bean class="org.apache.ignite.configuration.CacheConfiguration">
    <property name="name" value="spCache"/>
    <property name="cacheMode" value="PARTITIONED"/>
</bean>

Partycjonowanie według punktów sprzedaży zakłada, że potrzebny agregat zostanie zbudowany na każdym węźle klastra dla istniejących tam zapisów salesPointCache, a następnie węzeł klienta wykona ostateczne podsumowanie.

Czytam tutorial Pierwsza aplikacja Ignite Compute, robię analogicznie. Na każdym węźle klastra uruchamiam IgniteRunnable(), mniej więcej tak:

  @Override
  public void run() {
    SalesPoint sp=salesPointCache.get(spId);
    sp.calculateSalesPointCount();
    ..
  }

Dodaję logikę agregacji i eksportu, uruchamiam na próbce danych. Lokalne na serwerze deweloperskim wszystko działa.

Uruchamiam dwa testowe serwery CentOs, podaję adresy ip w default-config.xml, wykonuję na każdym

.\/bin\/ignite.sh config\/default-config.xml

Oba węzły Ignite uruchamiają się i widzą nawzajem. Podaję odpowiednie adresy w xml-konfigu klienta, uruchamia się i dodaje trzeci węzeł do topologii, a od razu liczba węzłów znów wynosi dwa. W logach pojawia się "ClassNotFoundException: model.SalesPoint" w linii

SalesPoint sp=salesPointCache.get(spId);

StackOverflow mówi, że przyczyna błędu — na serwerach CentOs brakuje klasy użytkownika SalesPoint. No cóż. Jak to "nie musisz ręcznie wdrażać swojego kodu Java na każdym węźle" i tak dalej? Czy "twój kod Java" — to nie dotyczy SalesPoint?

Prawdopodobnie coś przeoczyłem — znów zaczynam szukać, czytać i znów szukać. Po chwili pojawia się wrażenie, że przeczytałem już wszystko na ten temat, nic nowego nie ma. Podczas poszukiwań znalazłem kilka interesujących uwag.

Valentin Kulichenko, Lead Architect w GridGain Systems, odpowiedzi na StackOverflow, kwiecień 2016:

Klasy modelu nie są wdrażane równolegle, ale możesz użyć flagi withKeepBinary() na cache i zapytać BinaryObjects. W ten sposób unikniesz deserializacji po stronie serwera i nie dostaniesz ClassNotFoundException.

Jeszcze jedna autorytatywna opinia: Denis Magda, Dyrektor ds. zarządzania produktem w GridGain Systems.

Artykuł na Habrze o mikroserwisach odnosi się do trzech artykułów Denisa Magdy: Mikroserwisy Część I, Mikroserwisy Część II, Mikroserwisy Część III z lat 2016-2017. W drugim artykule Denis sugeruje uruchomienie węzła klastra za pomocą MaintenanceServiceNodeStartup.jar. Można także użyć uruchomienia z konfiguracją XML i wiersza poleceń, ale wtedy trzeba ręcznie umieścić klasy użytkownika na każdym wdrażanym węźle klastra:

To wszystko. Rozpocznij (..) węzeł używając pliku MaintenanceServiceNodeStartup lub przekaż maintenance-service-node-config.xml do skryptów ignite.sh/bat Apache Ignite. Jeśli wolisz to drugie, upewnij się, że zbudujesz plik jar, który będzie zawierał wszystkie klasy z katalogów java/app/common i java/services/maintenance. Plik jar musi być dodany do classpath każdego węzła, na którym może być wdrożona usługa.

Rzeczywiście, to wszystko. Oto on, okazuje się, ten tajemniczy format binarny!

3. SingleJar

Denis zajął pierwsze miejsce w moim osobistym rankingu, moim zdaniem to najprzydatniejszy samouczek ze wszystkich dostępnych. W jego MicroServicesExample na GitHubie znajduje się w pełni gotowy przykład konfiguracji węzłów klastra, który kompiluje się bez żadnych dodatkowych problemów.

Robię na wzór i podobieństwo, otrzymuję jeden plik jar, który uruchamia „data node” lub „client node” w zależności od argumentu wiersza poleceń. Kompilacja uruchamia się i działa. Zero Deployment pokonane.

Przejście od megabajtów testowych danych do dziesiątek gigabajtów bojowych pokazało, że format binarny istnieje z jakiegoś powodu. Konieczne było zoptymalizowanie wykorzystania pamięci na węzłach, a tutaj BinaryObject okazał się bardzo przydatny.

4. Wnioski

Pierwsze napotkane zarzuty dotyczące niejasności dokumentacji projektu Apache Ignite okazały się słuszne, od 2016 roku zmieniło się niewiele. Nowicjuszowi trudno jest zbudować działający prototyp na podstawie strony i/lub repozytorium.

Podsumowując wykonaną pracę, odniosłem wrażenie, że Zero Deployment działa, ale tylko na poziomie systemowym. Mniej więcej tak: BinaryObject jest stosowany, aby nauczyć zdalne węzły klastra współpracować z klasami użytkownika; Zero Deployment — wewnętrzny mechanizm
samego Apache Ignite i rozprowadza po klastrze obiekty systemowe.

Mam nadzieję, że moje doświadczenie będzie przydatne nowym użytkownikom Apache Ignite.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster