Kom igång med Reliable Services i Java

Den här artikeln beskriver grunderna i Azure Service Fabric Reliable Services och vägleder dig genom att skapa och distribuera ett enkelt Reliable Service-program som skrivits i Java.

På den här sidan finns en träningsvideo som visar hur du skapar en tillståndslös Reliable-tjänst:

Installation och installation

Innan du börjar kontrollerar du att du har konfigurerat Service Fabric-utvecklingsmiljön på datorn. Om du behöver konfigurera det går du till Komma igång med Mac eller komma igång med Linux.

Grundläggande begrepp

För att komma igång med Reliable Services behöver du bara förstå några grundläggande begrepp:

  • Tjänsttyp: Det här är din tjänstimplementering. Den definieras av den klass som du skriver som utökar StatelessService och andra kod- eller beroenden som används däri, tillsammans med ett namn och ett versionsnummer.
  • Namngiven tjänstinstans: Om du vill köra tjänsten skapar du namngivna instanser av din tjänsttyp, ungefär som du skapar objektinstanser av en klasstyp. Tjänstinstanser är i själva verket objektinstansieringar av din tjänstklass som du skriver.
  • Tjänstvärd: De namngivna tjänstinstanser som du skapar måste köras i en värd. Tjänstvärden är bara en process där instanser av tjänsten kan köras.
  • Tjänstregistrering: Registreringen sammanför allt. Tjänsttypen måste registreras med Service Fabric-körningen i en tjänstvärd för att Service Fabric ska kunna skapa instanser av den för att kunna köras.

Skapa en tillståndslös tjänst

Börja med att skapa ett Service Fabric-program. Service Fabric SDK för Linux innehåller en Yeoman-generator som tillhandahåller byggnadsställningar för ett Service Fabric-program med en tillståndslös tjänst. Börja med att köra följande Yeoman-kommando:

$ yo azuresfjava

Följ anvisningarna för att skapa en tillförlitlig tillståndslös tjänst. I den här självstudien namnger du programmet "HelloWorldApplication" och tjänsten "HelloWorld". Resultatet innehåller kataloger för HelloWorldApplication och HelloWorld.

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

Tjänstregistrering

Tjänsttyper måste registreras med Service Fabric-körningen. Tjänsttypen definieras i och ServiceManifest.xml din tjänstklass som implementerar StatelessService. Tjänstregistreringen utförs i processens huvudinmatningspunkt. I det här exemplet är HelloWorldServiceHost.javahuvudinmatningspunkten för processen :

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;
    }
}

Implementera tjänsten

Öppna HelloWorldApplication/HelloWorld/src/statelessservice/HelloWorldService.java. Den här klassen definierar tjänsttypen och kan köra valfri kod. Tjänst-API:et innehåller två startpunkter för koden:

  • En öppen startpunktsmetod med namnet runAsync(), där du kan börja köra alla arbetsbelastningar, inklusive långvariga beräkningsarbetsbelastningar.
@Override
protected CompletableFuture<?> runAsync(CancellationToken cancellationToken) {
    ...
}
  • En kommunikationsstartpunkt där du kan koppla in din kommunikationsstack. Här kan du börja ta emot begäranden från användare och andra tjänster.
@Override
protected List<ServiceInstanceListener> createServiceInstanceListeners() {
    ...
}

Den här självstudien runAsync() fokuserar på startpunktsmetoden. Det är här du omedelbart kan börja köra koden.

RunAsync

Plattformen anropar den här metoden när en instans av en tjänst placeras och är redo att köras. För en tillståndslös tjänst innebär det när tjänstinstansen öppnas. En annulleringstoken tillhandahålls för att samordna när din tjänstinstans måste stängas. I Service Fabric kan den här öppna/stäng-cykeln för en tjänstinstans inträffa många gånger under hela tjänstens livslängd. Detta kan inträffa av olika skäl, till exempel:

  • Systemet flyttar dina tjänstinstanser för resursutjämning.
  • Fel uppstår i koden.
  • Programmet eller systemet uppgraderas.
  • Den underliggande maskinvaran upplever ett avbrott.

Den här orkestreringen hanteras av Service Fabric för att hålla din tjänst högtillgänglig och korrekt balanserad.

runAsync() bör inte blockera synkront. Implementeringen av runAsync bör returnera en CompletableFuture så att körningen kan fortsätta. Om din arbetsbelastning behöver implementera en tidskrävande uppgift som ska utföras i CompletableFuture.

Annullering

Annulleringen av din arbetsbelastning är en samarbetsinsats som samordnas av den angivna annulleringstoken. Systemet väntar på att aktiviteten ska avslutas (genom slutförande, annullering eller fel) innan den fortsätter. Det är viktigt att respektera annulleringstoken, slutföra allt arbete och avsluta runAsync() så snabbt som möjligt när systemet begär annullering. I följande exempel visas hur du hanterar en annulleringshändelse:

@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){}
        }
    });
}

I det här tillståndslösa tjänstexemplet lagras antalet i en lokal variabel. Men eftersom det här är en tillståndslös tjänst finns värdet som lagras bara för den aktuella livscykeln för tjänstinstansen. När tjänsten flyttas eller startas om går värdet förlorat.

Skapa en tillståndskänslig tjänst

Service Fabric introducerar en ny typ av tjänst som är tillståndskänslig. En tillståndskänslig tjänst kan upprätthålla tillståndet på ett tillförlitligt sätt inom själva tjänsten, tillsammans med koden som använder den. Tillståndet görs högtillgängligt av Service Fabric utan att behöva bevara tillståndet för ett externt arkiv.

Om du vill konvertera ett räknarvärde från tillståndslöst till högtillgängligt och beständigt, även när tjänsten flyttas eller startas om, behöver du en tillståndskänslig tjänst.

I samma katalog som HelloWorld-programmet kan du lägga till en ny tjänst genom att yo azuresfjava:AddService köra kommandot . Välj "Reliable Stateful Service" för ditt ramverk och ge tjänsten namnet "HelloWorldStateful".

Ditt program bör nu ha två tjänster: den tillståndslösa tjänsten HelloWorld och den tillståndskänsliga tjänsten HelloWorldStateful.

En tillståndskänslig tjänst har samma startpunkter som en tillståndslös tjänst. Den största skillnaden är tillgängligheten för en tillståndsprovider som kan lagra tillståndet på ett tillförlitligt sätt. Service Fabric levereras med en implementering av tillståndsprovidern med namnet Reliable Collections, som gör att du kan skapa replikerade datastrukturer via Reliable State Manager. En tillståndskänslig Reliable Service använder den här tillståndsprovidern som standard.

Öppna HelloWorldStateful.java i HelloWorldStateful –> src, som innehåller följande RunAsync-metod:

@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() fungerar på samma sätt i tillståndskänsliga och tillståndslösa tjänster. Men i en tillståndskänslig tjänst utför plattformen ytterligare arbete åt dig innan den kör RunAsync(). Det här arbetet kan omfatta att se till att Reliable State Manager och Reliable Collections är redo att användas.

Reliable Collections och Reliable State Manager

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

ReliableHashMap är en ordlisteimplementering som du kan använda för att på ett tillförlitligt sätt lagra tillståndet i tjänsten. Med Service Fabric och Reliable HashMaps kan du lagra data direkt i tjänsten utan att behöva ett externt beständigt arkiv. Reliable HashMaps ger dina data hög tillgänglighet. Service Fabric gör detta genom att skapa och hantera flera repliker av tjänsten åt dig. Det tillhandahåller också ett API som abstraherar bort komplexiteten i hanteringen av dessa repliker och deras tillståndsövergångar.

Reliable Collections kan lagra valfri Java-typ, inklusive dina anpassade typer, med några varningar:

  • Service Fabric ger ditt tillstånd hög tillgänglighet genom att replikera tillstånd mellan noder, och Reliable HashMap lagrar dina data till en lokal disk på varje replik. Det innebär att allt som lagras i Reliable HashMaps måste vara serialiserbart.

  • Objekt replikeras för hög tillgänglighet när du genomför transaktioner på Reliable HashMaps. Objekt som lagras i Reliable HashMaps lagras i lokalt minne i tjänsten. Det innebär att du har en lokal referens till objektet.

    Det är viktigt att du inte muterar lokala instanser av dessa objekt utan att utföra en uppdateringsåtgärd på den tillförlitliga samlingen i en transaktion. Detta beror på att ändringar i lokala instanser av objekt inte replikeras automatiskt. Du måste återställa objektet till ordlistan eller använda någon av uppdateringsmetoderna i ordlistan.

Reliable State Manager hanterar Reliable HashMaps åt dig. Du kan när som helst och var som helst i tjänsten be Reliable State Manager om en tillförlitlig samling efter namn. Reliable State Manager ser till att du får tillbaka en referens. Vi rekommenderar inte att du sparar referenser till tillförlitliga samlingsinstanser i klassmedlemsvariabler eller egenskaper. Särskild försiktighet måste iakttas för att säkerställa att referensen alltid är inställd på en instans i tjänstens livscykel. Reliable State Manager hanterar det här arbetet åt dig och är optimerat för upprepade besök.

Transaktionella och asynkrona åtgärder

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());
    }
});

Åtgärder på Reliable HashMaps är asynkrona. Det beror på att skrivåtgärder med Reliable Collections utför I/O-åtgärder för att replikera och spara data till disk.

Tillförlitliga HashMap-åtgärder är transaktionella, så att du kan hålla tillståndet konsekvent över flera Reliable HashMaps och åtgärder. Du kan till exempel hämta ett arbetsobjekt från en Reliable Dictionary, utföra en åtgärd på den och spara resultatet i en annan Reliable HashMap, allt inom en enda transaktion. Detta behandlas som en atomisk åtgärd och garanterar att hela åtgärden lyckas eller att hela åtgärden återställs. Om ett fel uppstår efter att du har lagt objektet i kö men innan du sparar resultatet återställs hela transaktionen och objektet finns kvar i kön för bearbetning.

Skapa programmet

Yeoman-autogenereringen innehåller ett gradle-skript för att skapa program- och bash-skript för att distribuera och ta bort programmet. Om du vill köra programmet skapar du först programmet med gradle:

$ gradle

Detta skapar ett Service Fabric-programpaket som kan distribueras med Service Fabric CLI.

Distribuera programmet

När du har skapat programmet kan du distribuera det till det lokala klustret.

  1. Anslut till det lokala Service Fabric-klustret.

    sfctl cluster select --endpoint http://localhost:19080
    
  2. Kör installationsskriptet som medföljer mallen för att kopiera programpaketet till klustrets avbildningsarkiv, registrera programtypen och skapa en instans av programmet.

    ./install.sh
    

Distributionen går till på samma sätt som för andra Service Fabric-program. Detaljerade instruktioner finns i dokumentationen om att hantera ett Service Fabric-program med Service Fabric CLI.

Du hittar parametrarna till de här kommandona i de genererade manifesten i programpaketet.

När programmet har distribuerats öppnar du en webbläsare och går till Service Fabric Explorerhttp://localhost:19080/Explorer. Expandera sedan noden Program och observera att det nu finns en post för din programtyp och en post för den första instansen av den typen.

Viktigt

Om du vill distribuera programmet till ett säkert Linux-kluster i Azure måste du konfigurera ett certifikat för att verifiera ditt program med Service Fabric-körningen. På så sätt kan dina Reliable Services-tjänster kommunicera med de underliggande Service Fabric-runtime-API:erna. Mer information finns i Konfigurera en Reliable Services-app så att den körs på Linux-kluster.

Nästa steg