Delen via


Aan de slag met Reliable Services in Java

In dit artikel worden de basisbeginselen van Azure Service Fabric Reliable Services uitgelegd en wordt u begeleid bij het maken en implementeren van een eenvoudige Reliable Service-toepassing die is geschreven in Java.

Bekijk deze pagina voor een trainingsvideo waarin wordt getoond hoe u een stateless Reliable-service maakt:

Installatie en instellen

Voordat u begint, moet u ervoor zorgen dat de Service Fabric-ontwikkelomgeving op uw computer is ingesteld. Als u deze wilt instellen, gaat u naar aan de slag op Mac of aan de slag met Linux.

Basisbegrippen

Als u aan de slag wilt gaan met Reliable Services, hoeft u slechts enkele basisconcepten te begrijpen:

  • Servicetype: dit is uw service-implementatie. Deze wordt gedefinieerd door de klasse die u schrijft en StatelessService alle andere code of afhankelijkheden die daarin worden gebruikt, samen met een naam en een versienummer.
  • Benoemd service-exemplaar: Als u uw service wilt uitvoeren, maakt u benoemde exemplaren van uw servicetype, net zoals u objectexemplaren van een klassetype maakt. Service-exemplaren zijn in feite objectexemplaren van uw serviceklasse die u schrijft.
  • Servicehost: de benoemde service-exemplaren die u maakt, moeten worden uitgevoerd in een host. De servicehost is slechts een proces waarbij exemplaren van uw service kunnen worden uitgevoerd.
  • Serviceregistratie: Registratie brengt alles samen. Het servicetype moet worden geregistreerd bij de Service Fabric-runtime in een servicehost, zodat Service Fabric exemplaren kan maken die kunnen worden uitgevoerd.

Een stateless service maken

Begin met het maken van een Service Fabric-toepassing. De Service Fabric SDK voor Linux bevat een Yeoman-generator voor het leveren van de scaffolding voor een Service Fabric-toepassing met een stateless service. Begin met het uitvoeren van de volgende Yeoman-opdracht:

$ yo azuresfjava

Volg de instructies voor het maken van een betrouwbare stateless service. Geef voor deze zelfstudie de toepassing de naam 'HelloWorldApplication' en de service 'HelloWorld'. Het resultaat bevat mappen voor de HelloWorldApplication en 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

Serviceregistratie

Servicetypen moeten worden geregistreerd bij de Service Fabric-runtime. Het servicetype wordt gedefinieerd in de ServiceManifest.xml serviceklasse die wordt geïmplementeerd StatelessService. Serviceregistratie wordt uitgevoerd in het hoofdinvoerpunt van het proces. In dit voorbeeld is HelloWorldServiceHost.javahet hoofdinvoerpunt van het proces:

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

De service implementeren

Open HelloWorldApplication/HelloWorld/src/statelessservice/HelloWorldService.java. Deze klasse definieert het servicetype en kan elke code uitvoeren. De service-API biedt twee toegangspunten voor uw code:

  • Een open-ended ingangsmethode, genaamd runAsync(), waar u kunt beginnen met het uitvoeren van workloads, inclusief langlopende rekenworkloads.
@Override
protected CompletableFuture<?> runAsync(CancellationToken cancellationToken) {
    ...
}
  • Een communicatieinvoerpunt waar u uw communicatiestack naar keuze kunt aansluiten. Hier kunt u aanvragen ontvangen van gebruikers en andere services.
@Override
protected List<ServiceInstanceListener> createServiceInstanceListeners() {
    ...
}

Deze zelfstudie is gericht op de runAsync() invoerpuntmethode. Hier kunt u direct beginnen met het uitvoeren van uw code.

RunAsync

Het platform roept deze methode aan wanneer een exemplaar van een service wordt geplaatst en klaar is om uit te voeren. Voor een staatloze service betekent dit dat wanneer het service-exemplaar wordt geopend. Er wordt een annuleringstoken verstrekt om te coördineren wanneer uw service-exemplaar moet worden gesloten. In Service Fabric kan deze open/sluiten cyclus van een service-exemplaar zich vaak voordoen gedurende de levensduur van de service als geheel. Dit kan om verschillende redenen gebeuren, waaronder:

  • Het systeem verplaatst uw service-exemplaren voor resourceverdeling.
  • Er treden fouten op in uw code.
  • De toepassing of het systeem wordt bijgewerkt.
  • De onderliggende hardware ondervindt een storing.

Deze indeling wordt beheerd door Service Fabric om uw service maximaal beschikbaar en goed in balans te houden.

runAsync() mag niet synchroon worden geblokkeerd. De implementatie van runAsync moet een CompletableFuture retourneren om de runtime door te laten gaan. Als uw workload een langlopende taak moet implementeren die moet worden uitgevoerd in de CompletableFuture.

Opzegging

Annulering van uw workload is een gezamenlijke inspanning die wordt ingedeeld door het opgegeven annuleringstoken. Het systeem wacht totdat uw taak is beëindigd (door geslaagde voltooiing, annulering of fout) voordat de taak wordt uitgevoerd. Het is belangrijk om het annuleringstoken te respecteren, werk te voltooien en zo snel mogelijk af te sluiten runAsync() wanneer het systeem annulering aanvraagt. In het volgende voorbeeld ziet u hoe u een annulerings gebeurtenis kunt afhandelen:

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

In dit staatloze servicevoorbeeld wordt het aantal opgeslagen in een lokale variabele. Maar omdat dit een staatloze service is, bestaat de waarde die is opgeslagen alleen voor de huidige levenscyclus van het service-exemplaar. Wanneer de service wordt verplaatst of opnieuw wordt opgestart, gaat de waarde verloren.

Een stateful service maken

Service Fabric introduceert een nieuw type service dat stateful is. Een stateful service kan de status betrouwbaar binnen de service zelf onderhouden, samen met de code die deze gebruikt. De status wordt maximaal beschikbaar gesteld door Service Fabric zonder dat de status moet worden bewaard in een externe winkel.

Als u een tellerwaarde wilt converteren van staatloos naar maximaal beschikbaar en permanent, zelfs wanneer de service wordt verplaatst of opnieuw wordt opgestart, hebt u een stateful service nodig.

In dezelfde map als de HelloWorld-toepassing kunt u een nieuwe service toevoegen door de opdracht uit te yo azuresfjava:AddService voeren. Kies de 'Reliable Stateful Service' voor uw framework en geef de service de naam 'HelloWorldStateful'.

Uw toepassing moet nu twee services hebben: de stateless service HelloWorld en de stateful service HelloWorldStateful.

Een stateful service heeft dezelfde toegangspunten als een staatloze service. Het belangrijkste verschil is de beschikbaarheid van een statusprovider die de status betrouwbaar kan opslaan. Service Fabric wordt geleverd met een statusprovider-implementatie met de naam Reliable Collections, waarmee u gerepliceerde gegevensstructuren kunt maken via Reliable State Manager. Een stateful Reliable Service maakt standaard gebruik van deze statusprovider.

Open HelloWorldStateful.java in HelloWorldStateful -> src, die de volgende RunAsync-methode bevat:

@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() werkt op dezelfde manier in stateful en stateless services. In een stateful service voert het platform echter namens u extra werk uit voordat het wordt uitgevoerd RunAsync(). Dit werk kan omvatten om ervoor te zorgen dat Reliable State Manager en Reliable Collections gereed zijn voor gebruik.

Betrouwbare verzamelingen en de Reliable State Manager

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

ReliableHashMap is een woordenlijst-implementatie die u kunt gebruiken om de status betrouwbaar op te slaan in de service. Met Service Fabric en Reliable HashMaps kunt u gegevens rechtstreeks in uw service opslaan zonder dat hiervoor een extern permanent archief nodig is. Betrouwbare HashMaps maken uw gegevens maximaal beschikbaar. Service Fabric doet dit door meerdere replica's van uw service voor u te maken en te beheren. Het biedt ook een API waarmee de complexiteit van het beheren van deze replica's en hun statusovergangen wordt weggenomen.

Betrouwbare verzamelingen kunnen elk Java-type, inclusief uw aangepaste typen, opslaan met een aantal opmerkingen:

  • Service Fabric maakt uw status maximaal beschikbaar door de status over knooppunten te repliceren en Reliable HashMap slaat uw gegevens op op de lokale schijf op elke replica. Dit betekent dat alles wat is opgeslagen in Reliable HashMaps serialiseerbaar moet zijn.

  • Objecten worden gerepliceerd voor hoge beschikbaarheid wanneer u transacties doorvoert op Reliable HashMaps. Objecten die zijn opgeslagen in Reliable HashMaps, worden bewaard in het lokale geheugen in uw service. Dit betekent dat u een lokale verwijzing naar het object hebt.

    Het is belangrijk dat u lokale exemplaren van deze objecten niet muteert zonder een updatebewerking uit te voeren op de betrouwbare verzameling in een transactie. Dit komt doordat wijzigingen in lokale exemplaren van objecten niet automatisch worden gerepliceerd. U moet het object opnieuw in de woordenlijst invoegen of een van de updatemethoden in de woordenlijst gebruiken.

Reliable State Manager beheert Reliable HashMaps voor u. U kunt de Reliable State Manager op elk gewenst moment en op elke plaats in uw service vragen om een betrouwbare verzameling op naam. De Reliable State Manager zorgt ervoor dat u een referentie terug krijgt. We raden u niet aan verwijzingen op te slaan naar betrouwbare verzamelingsexemplaren in klasselidvariabelen of -eigenschappen. Zorg ervoor dat de verwijzing altijd is ingesteld op een exemplaar in de levenscyclus van de service. De Reliable State Manager verwerkt dit werk voor u en is geoptimaliseerd voor herhaalbezoeken.

Transactionele en asynchrone bewerkingen

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

Bewerkingen op betrouwbare hashmaps zijn asynchroon. Dit komt doordat schrijfbewerkingen met Reliable Collections I/O-bewerkingen uitvoeren om gegevens naar schijf te repliceren en te behouden.

Betrouwbare HashMap-bewerkingen zijn transactioneel, zodat u de status consistent kunt houden in meerdere Reliable HashMaps en bewerkingen. U kunt bijvoorbeeld een werkitem ophalen uit de ene Reliable Dictionary, er een bewerking op uitvoeren en het resultaat opslaan in een andere Reliable HashMap, allemaal binnen één transactie. Dit wordt behandeld als een atomische bewerking en garandeert dat de hele bewerking slaagt of dat de hele bewerking wordt teruggedraaid. Als er een fout optreedt nadat u het item uit de wachtrij hebt verwijderd, maar voordat u het resultaat opslaat, wordt de hele transactie teruggedraaid en blijft het item in de wachtrij voor verwerking.

De toepassing bouwen

De Yeoman-scaffolding bevat een gradle-script voor het bouwen van de toepassing en bash-scripts om de toepassing te implementeren en te verwijderen. Als u de toepassing wilt uitvoeren, bouwt u eerst de toepassing met gradle:

$ gradle

Dit produceert een Service Fabric-toepassingspakket dat kan worden geïmplementeerd met behulp van Service Fabric CLI.

De toepassing implementeren

Nadat de toepassing is gemaakt, kunt u deze implementeren in het lokale cluster.

  1. Maak verbinding met het lokale cluster van Service Fabric.

    sfctl cluster select --endpoint http://localhost:19080
    
  2. Voer het installatiescript uit dat is opgegeven in de sjabloon om het toepassingspakket te kopiëren naar de installatiekopieopslag van het cluster, het toepassingstype te registreren en een exemplaar van de toepassing te maken.

    ./install.sh
    

De implementatie van de gemaakte toepassing werkt hetzelfde als van andere Service Fabric-toepassingen. Zie de documentatie over het beheren van een Service Fabric-toepassing met de Service Fabric-CLI voor gedetailleerde instructies.

Parameters voor deze opdrachten vindt u in de gegenereerde manifesten binnen het toepassingspakket.

Nadat de toepassing is geïmplementeerd, opent u een browser en gaat u naar Service Fabric Explorer op http://localhost:19080/Explorer. Vouw vervolgens het knooppunt Toepassingen uit. U ziet dat er nu een vermelding is voor uw toepassingstype en nog een voor het eerste exemplaar van dat type.

Belangrijk

Als u de toepassing wilt implementeren in een beveiligd Linux-cluster in Azure, moet u een certificaat configureren om uw toepassing te valideren met de Service Fabric-runtime. Hierdoor kunnen uw Reliable Services-services communiceren met de onderliggende Service Fabric Runtime-API's. Zie Een Reliable Services-app configureren voor uitvoering op Linux-clusters voor meer informatie.

Volgende stappen