Wdrożenie Apache Ignite Zero: naprawdę zero?

Wdrożenie Apache Ignite Zero: naprawdę zero?

Jesteśmy działem rozwoju technologii sieci detalicznej. Pewnego dnia kierownictwo postawiło sobie za zadanie przyspieszenie obliczeń na dużą skalę za pomocą Apache Ignite w połączeniu z MSSQL i pokazało stronę internetową z pięknymi ilustracjami i przykładami kodu Java. Strona od razu mi się spodobała Zerowe wdrożenie, którego opis obiecuje cuda: nie musisz ręcznie wdrażać kodu Java lub Scala w każdym węźle gridu i wdrażać go ponownie za każdym razem, gdy się zmieni. W miarę postępu prac okazało się, że Zero Deployment ma specyficzne zastosowania, którymi chcę się podzielić. Poniżej cięcia znajdują się przemyślenia i szczegóły realizacji.

1. Stwierdzenie problemu

Istota problemu jest następująca. Istnieje katalog punktów sprzedaży SalesPoint i katalog produktów SKU (jednostki magazynowania). Punkt sprzedaży posiada atrybut „Typ sklepu” z wartościami „mały” i „duży”. Do każdego punktu sprzedaży podłączony jest asortyment (lista produktów danego punktu sprzedaży) (pobierana z SZBD) i podana jest informacja, że ​​od określonej daty określony produkt
wyłączone z asortymentu lub dodane do asortymentu.

Wymagane jest zorganizowanie partycjonowanej pamięci podręcznej punktów sprzedaży i przechowywanie w niej informacji o połączonych produktach z miesięcznym wyprzedzeniem. Zgodność z systemem walki wymaga, aby węzeł kliencki Ignite wczytał dane, obliczył agregat formularza (typ sklepu, kod produktu, dzień, liczba_punktów_sprzedaży) i wgrał go z powrotem do DBMS.

2. Studium literatury

Nie mam jeszcze żadnego doświadczenia, więc zaczynam tańczyć z pieca. To znaczy z przeglądu publikacji.

Artykuł z 2016 roku Przedstawiamy Apache Ignite: pierwsze kroki zawiera odnośnik do dokumentacji projektu Apache Ignite i jednocześnie zarzut niejasności tej dokumentacji. Czytam to jeszcze raz kilka razy i nie ma dla mnie jasności. Odsyłam do oficjalnego poradnika pierwsze krokiKtóry
optymistycznie obiecuje: „Za chwilę będziesz gotowy do pracy!” Zastanawiam się nad ustawieniami zmiennych środowiskowych, oglądając dwa filmy o Apache Ignite Essentials, ale nie były one zbyt przydatne w przypadku mojego konkretnego zadania. Pomyślnie uruchamiam Ignite z linii poleceń ze standardowym plikiem „example-ignite.xml”, budując pierwszą aplikację Aplikacja obliczeniowa za pomocą Mavena. Aplikacja działa i wykorzystuje Zero Deployment, co za piękność!

Czytam dalej i tam w przykładzie od razu zastosowano affinityKey (utworzony wcześniej poprzez zapytanie SQL), a nawet zastosowano tajemniczy obiekt BinaryObject:

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

Czytać nieznacznie: format binarny - coś w rodzaju refleksji, dostępu do pól obiektu po nazwie. Potrafi odczytać wartość pola bez całkowitej deserializacji obiektu (oszczędność pamięci). Ale dlaczego zamiast Person używany jest BinaryObject, skoro wdrożenie jest zerowe? Dlaczego IgniteCache przeniesione do IgniteCache ? Nie jest to jeszcze jasne.

Przerabiam aplikację obliczeniową, aby pasowała do mojego przypadku. Klucz podstawowy katalogu punktów sprzedaży w MSSQL jest zdefiniowany jako [id] [int] NOT NULL, ja tworzę pamięć podręczną analogicznie

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

W konfiguracji XML wskazuję, że pamięć podręczna jest podzielona na partycje

<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 ​​na każdym węźle klastra zostanie zbudowana wymagana agregacja dla dostępnych tam rekordów salesPointCache, po czym węzeł klienta dokona ostatecznego podsumowania.

Czytam tutorial Aplikacja First Ignite Compute, robię to przez analogię. Na każdym węźle klastra uruchamiam IgniteRunnable(), coś takiego:

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

Dodaję logikę agregacji i przesyłania i uruchamiam ją na testowym zestawie danych. Wszystko działa lokalnie na serwerze deweloperskim.

Uruchamiam dwa serwery testowe CentOs, podaję adresy IP w pliku default-config.xml, uruchamiam na każdym

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

Obydwa węzły Ignite działają i widzą się nawzajem. Podaję wymagane adresy w konfiguracji xml aplikacji klienckiej, uruchamia się, dodaje trzeci węzeł do topologii i natychmiast znów pojawiają się dwa węzły. Dziennik zawiera wiersz „ClassNotFoundException: model.SalesPoint”.

SalesPoint sp=salesPointCache.get(spId);

StackOverflow twierdzi, że przyczyną błędu jest brak niestandardowej klasy SalesPoint na serwerach CentOs. Dotarliśmy. A co powiesz na to, że „nie musisz ręcznie wdrażać kodu Java w każdym węźle” i tak dalej? A może „Twój kod Java” nie dotyczy SalesPoint?

Pewnie coś przeoczyłem – zaczynam szukać od nowa, czytać i szukać od nowa. Po chwili mam wrażenie, że przeczytałem już wszystko na ten temat, nie ma już nic nowego. Szukając znalazłem kilka ciekawych komentarzy.

Walenty Kuliczenko, główny architekt w GridGain Systems, odpowiedź na StackOverflow, kwiecień 2016:

Model classes are not peer deployed, but you can use withKeepBinary() flag
on the cache and query BinaryObjects. This way you will avoid deserialization
on the server side and will not get ClassNotFoundException.

Kolejna autorytatywna opinia: Denis Magda, Dyrektor ds. zarządzania produktami, GridGain Systems.

Artykuł o Habré o mikroserwisach przywołuje trzy artykuły Denisa Magdy: Mikroserwisy Część I, Mikroserwisy Część II, Mikrousługi Część III 2016-2017. W drugim artykule Denis sugeruje uruchomienie węzła klastra za pośrednictwem pliku MaintenanceServiceNodeStartup.jar. Możesz także użyć opcji uruchamiania z konfiguracją XML i wierszem poleceń, ale wtedy musisz ręcznie umieścić niestandardowe klasy w każdym wdrożonym węźle klastra:

That's it. Start (..)  node using MaintenanceServiceNodeStartup file or pass
maintenance-service-node-config.xml to Apache Ignite's ignite.sh/bat scripts.
If you prefer the latter then make sure to build a jar file that will contain
all the classes from java/app/common and java/services/maintenance directories.
The jar has to be added to the classpath of every node where the service
might be deployed.

Rzeczywiście, to wszystko. Tutaj okazuje się, dlaczego ten tajemniczy format binarny!

3. Pojedynczy słoik

Denis zajął pierwsze miejsce w mojej osobistej ocenie, IMHO najbardziej przydatny tutorial ze wszystkich dostępnych. W jego Przykład mikrousług Github zawiera całkowicie gotowy przykład konfiguracji węzłów klastra, który kompiluje się bez dodatkowego kucania.

Robię to w ten sam sposób i otrzymuję pojedynczy plik jar, który uruchamia „węzeł danych” lub „węzeł klienta” w zależności od argumentu wiersza poleceń. Montaż rozpoczyna się i działa. Wdrożenie zerowe zostało pokonane.

Przejście z megabajtów danych testowych do dziesiątek gigabajtów danych bojowych pokazało, że format binarny istnieje nie bez powodu. Należało zoptymalizować zużycie pamięci na węzłach i tutaj bardzo przydatny okazał się BinaryObject.

4. Wnioski

Pierwszy zarzut dotyczący niejasności dokumentacji projektu Apache Ignite okazał się słuszny, od 2016 roku niewiele się zmieniło. Początkującemu nie jest łatwo złożyć działający prototyp w oparciu o stronę internetową i/lub repozytorium.

Na podstawie wyników wykonanej pracy można odnieść wrażenie, że Zero Deployment działa, ale tylko na poziomie systemu. Coś w tym stylu: BinaryObject służy do uczenia zdalnych węzłów klastra pracy z klasami niestandardowymi; Zero Deployment – ​​mechanizm wewnętrzny
Apache Ignite sam rozprowadza obiekty systemowe po całym klastrze.

Mam nadzieję, że moje doświadczenie przyda się nowym użytkownikom Apache Ignite.

Źródło: www.habr.com

Dodaj komentarz