Wprowadzenie do usług Reliable Services w języku Java

W tym artykule wyjaśniono podstawy usługi Azure Service Fabric Reliable Services i przedstawiono sposób tworzenia i wdrażania prostej aplikacji Usługi Reliable Service napisanej w języku Java.

Sprawdź tę stronę, aby zapoznać się z filmem wideo szkoleniowym, w którym pokazano, jak utworzyć bezstanową usługę Reliable Service:

Instalacja i konfiguracja

Przed rozpoczęciem upewnij się, że na maszynie jest skonfigurowane środowisko programistyczne usługi Service Fabric. Jeśli musisz go skonfigurować, przejdź do artykułu Wprowadzenie do komputerów Mac lub wprowadzenie do systemu Linux.

Podstawowe pojęcia

Aby rozpocząć pracę z usługami Reliable Services, musisz zrozumieć tylko kilka podstawowych pojęć:

  • Typ usługi: Jest to implementacja usługi. Jest on definiowany StatelessService przez klasę, która rozszerza się, oraz wszelkie inne kod lub zależności użyte tam wraz z nazwą i numerem wersji.
  • Nazwane wystąpienie usługi: aby uruchomić usługę, należy utworzyć nazwane wystąpienia typu usługi, podobnie jak w przypadku tworzenia wystąpień obiektów typu klasy. Wystąpienia usługi są w rzeczywistości wystąpieniami obiektów klasy usługi, którą piszesz.
  • Host usługi: utworzone wystąpienia usługi muszą być uruchamiane wewnątrz hosta. Host usługi to tylko proces, w którym można uruchamiać wystąpienia usługi.
  • Rejestracja usługi: Rejestracja łączy wszystko razem. Typ usługi musi być zarejestrowany w środowisku uruchomieniowym usługi Service Fabric na hoście usługi, aby umożliwić usłudze Service Fabric tworzenie wystąpień do uruchomienia.

Tworzenie usługi bezstanowej

Rozpocznij od utworzenia aplikacji usługi Service Fabric. Zestaw SDK usługi Service Fabric dla systemu Linux zawiera generator Yeoman zapewniający szkielet aplikacji usługi Service Fabric z usługą bezstanową. Rozpocznij od uruchomienia następującego polecenia Narzędzia Yeoman:

$ yo azuresfjava

Postępuj zgodnie z instrukcjami, aby utworzyć niezawodną usługę bezstanową. W tym samouczku nadaj aplikacji nazwę "HelloWorldApplication" i usługę "HelloWorld". Wynik zawiera katalogi dla i HelloWorldApplicationHelloWorld.

HelloWorldApplication/
├── build.gradle
├── HelloWorld
│   ├── build.gradle
│   └── src
│       └── statelessservice
│           ├── HelloWorldServiceHost.java
│           └── HelloWorldService.java
├── HelloWorldApplication
│   ├── ApplicationManifest.xml
│   └── HelloWorldPkg
│       ├── Code
│       │   ├── entryPoint.sh
│       │   └── _readme.txt
│       ├── Config
│       │   └── _readme.txt
│       ├── Data
│       │   └── _readme.txt
│       └── ServiceManifest.xml
├── install.sh
├── settings.gradle
└── uninstall.sh

Rejestracja usługi

Typy usług muszą być zarejestrowane w środowisku uruchomieniowym usługi Service Fabric. Typ usługi jest zdefiniowany w ServiceManifest.xml klasie i usługi, która implementuje StatelessServiceelement . Rejestracja usługi jest wykonywana w głównym punkcie wejścia procesu. W tym przykładzie główny punkt wejścia procesu to HelloWorldServiceHost.java:

public static void main(String[] args) throws Exception {
    try {
        ServiceRuntime.registerStatelessServiceAsync("HelloWorldType", (context) -> new HelloWorldService(), Duration.ofSeconds(10));
        logger.log(Level.INFO, "Registered stateless service type HelloWorldType.");
        Thread.sleep(Long.MAX_VALUE);
    }
    catch (Exception ex) {
        logger.log(Level.SEVERE, "Exception in registration:", ex);
        throw ex;
    }
}

Implementowanie usługi

Otwórz plik HelloWorldApplication/HelloWorld/src/statelessservice/HelloWorldService.java. Ta klasa definiuje typ usługi i może uruchomić dowolny kod. Interfejs API usługi udostępnia dwa punkty wejścia dla kodu:

  • Otwarta metoda punktu wejścia o nazwie runAsync(), w której można rozpocząć wykonywanie dowolnych obciążeń, w tym długotrwałych obciążeń obliczeniowych.
@Override
protected CompletableFuture<?> runAsync(CancellationToken cancellationToken) {
    ...
}
  • Punkt wejścia komunikacji, w którym można podłączyć wybrany stos komunikacji. W tym miejscu można rozpocząć odbieranie żądań od użytkowników i innych usług.
@Override
protected List<ServiceInstanceListener> createServiceInstanceListeners() {
    ...
}

Ten samouczek koncentruje się na metodzie runAsync() punktu wejścia. W tym miejscu możesz natychmiast rozpocząć uruchamianie kodu.

RunAsync

Platforma wywołuje tę metodę, gdy zostanie umieszczone wystąpienie usługi i będzie gotowe do wykonania. W przypadku usługi bezstanowej oznacza to, że po otwarciu wystąpienia usługi. Token anulowania jest udostępniany do koordynowania, gdy wystąpienie usługi musi zostać zamknięte. W usłudze Service Fabric ten cykl otwierania/zamykania wystąpienia usługi może wystąpić wiele razy w całym okresie istnienia usługi. Może się to zdarzyć z różnych powodów, w tym:

  • System przenosi wystąpienia usługi na potrzeby równoważenia zasobów.
  • Błędy występują w kodzie.
  • Aplikacja lub system jest uaktualniana.
  • Podstawowy sprzęt doświadcza awarii.

Ta aranżacja jest zarządzana przez usługę Service Fabric w celu zapewnienia wysokiej dostępności i prawidłowego zrównoważenia usługi.

runAsync() nie należy blokować synchronicznie. Implementacja polecenia runAsync powinna zwrócić completableFuture, aby umożliwić kontynuowanie środowiska uruchomieniowego. Jeśli obciążenie musi zaimplementować długotrwałe zadanie, które należy wykonać wewnątrz completableFuture.

Anulowanie

Anulowanie obciążenia to wspólny wysiłek zaplanowany przez podany token anulowania. System czeka na zakończenie zadania (po pomyślnym zakończeniu, anulowaniu lub błędzie), zanim przejdzie dalej. Ważne jest, aby uhonorować token anulowania, zakończyć pracę i zamknąć runAsync() tak szybko, jak to możliwe, gdy system żąda anulowania. W poniższym przykładzie pokazano, jak obsłużyć zdarzenie anulowania:

@Override
protected CompletableFuture<?> runAsync(CancellationToken cancellationToken) {

    // TODO: Replace the following sample code with your own logic
    // or remove this runAsync override if it's not needed in your service.

    return CompletableFuture.runAsync(() -> {
        long iterations = 0;
        while(true)
        {
        cancellationToken.throwIfCancellationRequested();
        logger.log(Level.INFO, "Working-{0}", ++iterations);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex){}
        }
    });
}

W tym przykładzie usługi bezstanowej liczba jest przechowywana w zmiennej lokalnej. Ponieważ jest to usługa bezstanowa, wartość przechowywana istnieje tylko dla bieżącego cyklu życia wystąpienia usługi. Gdy usługa zostanie przeniesiona lub ponownie uruchomiona, wartość zostanie utracona.

Tworzenie usługi stanowej

Usługa Service Fabric wprowadza nowy rodzaj usługi, która jest stanowa. Usługa stanowa może niezawodnie obsługiwać stan w samej usłudze, współlokacyjnie z kodem, który go używa. Stan jest wysoce dostępny przez usługę Service Fabric bez konieczności utrwalania stanu w magazynie zewnętrznym.

Aby przekonwertować wartość licznika z bezstanowej na wysoce dostępną i trwałą, nawet jeśli usługa zostanie przeniesiona lub uruchomiona ponownie, potrzebna jest usługa stanowa.

W tym samym katalogu co aplikacja HelloWorld możesz dodać nową usługę yo azuresfjava:AddService , uruchamiając polecenie . Wybierz usługę "Reliable Stateful Service" dla platformy i nadaj jej nazwę "HelloWorldStateful".

Aplikacja powinna teraz mieć dwie usługi: bezstanową usługę HelloWorld i stanową usługę HelloWorldStateful.

Usługa stanowa ma te same punkty wejścia co usługa bezstanowa. Główną różnicą jest dostępność dostawcy stanu, który może niezawodnie przechowywać stan. Usługa Service Fabric jest dostarczana z implementacją dostawcy stanu o nazwie Reliable Collections, która umożliwia tworzenie zreplikowanych struktur danych za pomocą usługi Reliable State Manager. Stanowa usługa Reliable Service domyślnie używa tego dostawcy stanu.

Otwórz plik HelloWorldStateful.java w pliku HelloWorldStateful —> src, który zawiera następującą metodę RunAsync:

@Override
protected CompletableFuture<?> runAsync(CancellationToken cancellationToken) {
    Transaction tx = stateManager.createTransaction();
    return this.stateManager.<String, Long>getOrAddReliableHashMapAsync("myHashMap").thenCompose((map) -> {
        return map.computeAsync(tx, "counter", (k, v) -> {
            if (v == null)
                return 1L;
            else
                return ++v;
            }, Duration.ofSeconds(4), cancellationToken)
                .thenCompose((r) -> tx.commitAsync())
                .whenComplete((r, e) -> {
            try {
                tx.close();
            } catch (Exception e) {
                logger.log(Level.SEVERE, e.getMessage());
            }
        });
    });
}

RunAsync

RunAsync() działa podobnie w usługach stanowych i bezstanowych. Jednak w usłudze stanowej platforma wykonuje dodatkową pracę w Twoim imieniu przed wykonaniem RunAsync()polecenia . Ta praca może obejmować zapewnienie, że niezawodne usługi State Manager i Reliable Collections są gotowe do użycia.

Niezawodne kolekcje i niezawodny menedżer stanu

ReliableHashMap<String,Long> map = this.stateManager.<String, Long>getOrAddReliableHashMapAsync("myHashMap")

ReliableHashMap to implementacja słownika, której można użyć do niezawodnego przechowywania stanu w usłudze. Za pomocą usług Service Fabric i Reliable HashMaps można przechowywać dane bezpośrednio w usłudze bez konieczności zewnętrznego magazynu trwałego. Niezawodne mapy skrótów zapewniają wysoką dostępność danych. Usługa Service Fabric umożliwia utworzenie wielu replik usługi i zarządzanie nimi. Udostępnia również interfejs API, który oddziela złożoność zarządzania tymi replikami i ich przejściami stanu.

Kolekcje Reliable Mogą przechowywać dowolny typ języka Java, w tym typy niestandardowe, z kilkoma zastrzeżeniami:

  • Usługa Service Fabric zapewnia wysoką dostępność, replikując stan między węzłami, a funkcja Reliable HashMap przechowuje dane na dysku lokalnym na każdej repliki. Oznacza to, że wszystkie elementy przechowywane w elementach Reliable HashMaps muszą być serializowalne.

  • Obiekty są replikowane w celu zapewnienia wysokiej dostępności podczas zatwierdzania transakcji w elementach Reliable HashMaps. Obiekty przechowywane w elementach Reliable HashMaps są przechowywane w pamięci lokalnej w usłudze. Oznacza to, że masz lokalne odwołanie do obiektu.

    Ważne jest, aby nie mutować lokalnych wystąpień tych obiektów bez wykonywania operacji aktualizacji na niezawodnej kolekcji w transakcji. Dzieje się tak, ponieważ zmiany w lokalnych wystąpieniach obiektów nie będą replikowane automatycznie. Należy ponownie przenieść obiekt do słownika lub użyć jednej z metod aktualizacji w słowniku.

Narzędzie Reliable State Manager zarządza niezawodnymi mapami skrótów. W dowolnym momencie i w dowolnym miejscu usługi możesz poprosić menedżera reliable state manager o niezawodną kolekcję według nazwy. Usługa Reliable State Manager zapewnia, że otrzymasz odwołanie z powrotem. Nie zalecamy zapisywania odwołań do niezawodnych wystąpień kolekcji w zmiennych lub właściwościach składowych klasy. Należy zachować szczególną ostrożność, aby upewnić się, że odwołanie jest ustawione na wystąpienie przez cały czas w cyklu życia usługi. Niezawodna usługa State Manager obsługuje tę pracę za Ciebie i jest zoptymalizowana pod kątem powtarzanych wizyt.

Operacje transakcyjne i asynchroniczne

return map.computeAsync(tx, "counter", (k, v) -> {
    if (v == null)
        return 1L;
    else
        return ++v;
    }, Duration.ofSeconds(4), cancellationToken)
        .thenCompose((r) -> tx.commitAsync())
        .whenComplete((r, e) -> {
    try {
        tx.close();
    } catch (Exception e) {
        logger.log(Level.SEVERE, e.getMessage());
    }
});

Operacje na mapach Reliable HashMap są asynchroniczne. Jest to spowodowane tym, że operacje zapisu z niezawodnymi kolekcjami wykonują operacje we/wy w celu replikowania i utrwalania danych na dysku.

Operacje Reliable HashMap są transakcyjne, dzięki czemu można zachować spójność stanu na wielu mapach i operacjach Reliable HashMap. Możesz na przykład pobrać element roboczy z jednego słownika Reliable Dictionary, wykonać na nim operację i zapisać wynik w innym elemencie Reliable HashMap , a wszystko to w ramach jednej transakcji. Jest to traktowane jako operacja niepodzielna i gwarantuje, że cała operacja powiedzie się lub cała operacja zostanie wycofana. Jeśli po usunięciu elementu z kolejki wystąpi błąd, ale przed zapisaniem wyniku, cała transakcja zostanie wycofana, a element pozostanie w kolejce do przetworzenia.

Kompilowanie aplikacji

Tworzenie szkieletu narzędzia Yeoman obejmuje skrypt narzędzia gradle służący do kompilowania aplikacji i skryptów powłoki bash w celu wdrożenia i usunięcia aplikacji. Aby uruchomić aplikację, najpierw skompiluj aplikację za pomocą narzędzia gradle:

$ gradle

Spowoduje to utworzenie pakietu aplikacji usługi Service Fabric, który można wdrożyć przy użyciu interfejsu wiersza polecenia usługi Service Fabric.

Wdrażanie aplikacji

Skompilowaną aplikację można wdrożyć w klastrze lokalnym.

  1. Połącz się z lokalnym klastrem usługi Service Fabric.

    sfctl cluster select --endpoint http://localhost:19080
    
  2. Uruchom skrypt instalacji udostępniony w szablonie, aby skopiować pakiet aplikacji do magazynu obrazów klastra, zarejestrować typ aplikacji i utworzyć wystąpienie aplikacji.

    ./install.sh
    

Wdrażanie skompilowanej aplikacji przebiega tak samo jak w przypadku innych aplikacji usługi Service Fabric. Szczegółowe instrukcje są dostępne w dokumentacji dotyczącej zarządzania aplikacją usługi Service Fabric za pomocą interfejsu wiersza polecenia usługi Service Fabric.

Parametry tych poleceń można znaleźć w manifestach wygenerowanych w pakiecie aplikacji.

Po wdrożeniu aplikacji otwórz przeglądarkę i przejdź do narzędzia Service Fabric Explorer pod adresem http://localhost:19080/Explorer. Następnie rozwiń węzeł Aplikacje i zwróć uwagę, że istnieje teraz wpis dla danego typu aplikacji i inny wpis dla pierwszego wystąpienia tego typu.

Ważne

Aby wdrożyć aplikację w bezpiecznym klastrze systemu Linux na platformie Azure, należy skonfigurować certyfikat w celu zweryfikowania aplikacji przy użyciu środowiska uruchomieniowego usługi Service Fabric. Dzięki temu usługi Reliable Services mogą komunikować się z podstawowymi interfejsami API środowiska uruchomieniowego usługi Service Fabric. Aby dowiedzieć się więcej, zobacz Konfigurowanie aplikacji Reliable Services do uruchamiania w klastrach systemu Linux.

Następne kroki