Vejledning til reaktive mikrotjenester ved hjælp af Lagom Framework

1. Oversigt

I denne artikel undersøger vi Lagom-rammen og implementere en eksempelapplikation ved hjælp af en reaktiv mikrotjenestedrevet arkitektur.

Kort sagt, reaktive softwareapplikationer er afhængige af meddelelsesdrevet asynkron kommunikation og er meget stærke Lydhør, Robust og Elastisk i naturen.

Med mikroservicedrevet arkitektur mente vi at opdele systemet i grænser mellem samarbejdstjenester for at nå målene for Isolation, Autonomi, Enkelt ansvar, Mobilitetosv. For yderligere læsning af disse to begreber henvises til The Reactive Manifesto and Reactive Microservices Architecture.

2. Hvorfor Lagom?

Lagom er en open source-ramme bygget med overgangen fra monolit til mikrotjenestedrevet applikationsarkitektur. Det abstraherer kompleksiteten ved opbygning, kørsel og overvågning af mikrotjenester drevne applikationer.

Bag kulisserne bruger Lagom framework Play Framework, en Akka-meddelelsesdrevet runtime, Kafka til afkoblingstjenester, Event Sourcing og CQRS-mønstre og ConductR-understøttelse til overvågning og skalering af mikrotjenester i containermiljøet.

3. Hej verden i Lagom

Vi opretter en Lagom-applikation til at håndtere en hilsenanmodning fra brugeren og svare tilbage med en hilsenbesked sammen med vejrstatistikker for dagen.

Og vi udvikler to separate mikrotjenester: Hilsen og Vejr.

Hilsen vil fokusere på håndtering af en hilsenanmodning, interagere med vejretjenesten for at svare tilbage til brugeren. Det Vejr microservice vil servicere anmodningen om vejrstatistikker til i dag.

I tilfælde af eksisterende bruger, der interagerer med Hilsen mikroservice, vises den forskellige hilsen til brugeren.

3.1. Forudsætninger

  1. Installere Scala (vi bruger i øjeblikket 2.11.8 version) herfra
  2. Installere sbt build-værktøj (vi bruger i øjeblikket 0.13.11) herfra

4. Opsætning af projekt

Lad os nu se hurtigt på trinene til opsætning af et fungerende Lagom-system.

4.1. SBT Build

Opret en projektmappe lagom-hej-verden efterfulgt af build-filenbuild.sbt. Et Lagom-system består typisk af et sæt sbt bygger med hver build svarende til en gruppe relaterede tjenester:

organisation i ThisBuild: = "com.baeldung" scalaVersion i ThisBuild: = "2.11.8" lagomKafkaEnabled i ThisBuild: = falske lazy val greetingApi = projekt ("greeting-api") .settings (version: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslApi)) lazy val greetingImpl = project ("greeting-impl"). enablePlugins (LagomJava) .settings (version: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslPersistenceCassandra)) .dependsOn greetingApi, weatherApi) doven val weatherApi = projekt ("weather-api") .settings (version: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslApi)) doven val weatherImpl = projekt ("weather-impl"). enablePlugins (LagomJava) .settings (version: = "1.0-SNAPSHOT") .dependsOn (weatherApi) def projekt (id: String) = Projekt (id, base = fil (id))

Til at begynde med har vi specificeret organisationsoplysningerne, scala version og deaktiveret Kafka til det aktuelle projekt. Lagom følger en konvention af to separate projekter for hver mikroservice: API-projekt og et implementeringsprojekt.

API-projektet indeholder den serviceinterface, som implementeringen afhænger af.

Vi har tilføjet afhængigheder til de relevante Lagom-moduler som f.eks lagomJavadslApi, lagomJavadslPersistensCassandra til brug af Lagom Java API i vores mikrotjenester og lagring af begivenheder relateret til den vedvarende enhed i Cassandra, henholdsvis.

Også den hilsen-impl projektet afhænger af vejr-api projekt for at hente og servere vejrstatistikker, mens du hilser en bruger.

Understøttelse af Lagom-pluginet tilføjes ved at oprette en plugin-mappe med plugins.sbt fil, har en post til Lagom-plugin. Det giver al den nødvendige support til opbygning, kørsel og implementering af vores applikation.

Også den sbteclipse plugin vil være praktisk, hvis vi bruger Eclipse IDE til dette projekt. Koden nedenfor viser indholdet af begge plugins:

addSbtPlugin ("com.lightbend.lagom"% "lagom-sbt-plugin"% "1.3.1") addSbtPlugin ("com.typesafe.sbteclipse"% "sbteclipse-plugin"% "3.0.0")

skab projekt / build.properties fil og angiv sbt version, der skal bruges:

sbt.version = 0.13.11

4.2. Projektgenerering

Løb sbt kommando fra projektroden genererer følgende projektskabeloner:

  1. hilsen-api
  2. hilsen-impl
  3. vejr-api
  4. vejr-impl

Før vi begynder at implementere mikroservices, lad os tilføje src / main / java og src / main / java / ressourcer mapper inde i hvert af projekterne for at følge Maven-lignende projektmappelayout.

Der genereres også to dynamiske projekter indeni projekt-rod / mål / lagom-dynamisk-projekter:

  1. lagom-intern-meta-projekt-kassandra
  2. lagom-intern-meta-projekt-service-locator

Disse projekter bruges internt af Lagom.

5. Serviceinterface

I hilsen-api projekt, specificerer vi følgende grænseflade:

offentlig grænseflade GreetingService udvider Service {public ServiceCall handleGreetFrom (strengbruger); @ Override standard Descriptor descriptor () {return named ("greetingservice") .withCalls (restCall (Method.GET, "/ api / greeting /: fromUser", this :: handleGreetFrom)) .withAutoAcl (true); }}

HilsenService afslører handleGreetFrom () til at håndtere hilsen fra brugeren. EN ServiceCall API bruges som returtype for disse metoder. ServiceCall tager to typeparametre Anmodning og Respons.

Det Anmodning parameter er typen af ​​meddelelsen om indgående anmodning og Respons parameter er typen af ​​den udgående svarmeddelelse.

I eksemplet ovenfor bruger vi ikke anmodningens nyttelast, anmodningstypen er Anvendes ikkeog Respons typen er en Snor hilsen besked.

HilsenService specificerer også en kortlægning til den faktiske transport, der blev brugt under påkaldelsen, ved at give en standardimplementering af Service.descriptor () metode. En tjeneste navngivet hilsen service returneres.

handleGreetFrom () serviceopkald kortlægges ved hjælp af en rest-id: metodetype og stiidentifikator / api / hilsen /: fra bruger kortlagt til handleGreetFrom () metode. Tjek dette link for at få flere oplysninger om service-id'er.

På de samme linjer definerer vi WeatherService interface i vejr-api projekt. weatherStatsForToday () metode og deskriptor () metode er stort set selvforklarende:

offentlig grænseflade WeatherService udvider Service {public ServiceCall weatherStatsForToday (); @Override standard Descriptor descriptor () {return called ("weatherservice") .withCalls (restCall (Method.GET, "/ api / weather", this :: weatherStatsForToday)) .withAutoAcl (true); }};

WeatherStats er defineret som en enum med prøveværdier for forskellige vejrforhold og tilfældig opslag for at returnere vejrudsigten for dagen:

offentlig enum WeatherStats {STATS_RAINY ("Gå til regn, tag paraply"), STATS_HUMID ("Bliver meget fugtig, tag vand"); offentlige statiske WeatherStats forToday () {return VALUES.get (RANDOM.nextInt (SIZE)); }}

6. Lagom Persistence - Begivenhedssourcing

Kort sagt, i et system, der bruger Arrangementssourcing, vil vi være i stand til at registrere alle ændringer, da uforanderlige domænehændelser tilføjes den ene efter den anden. Den aktuelle tilstand er afledt ved afspilning og behandling af begivenheder. Denne operation er i det væsentlige en fold venstre operation kendt fra Funktionel programmering paradigme.

Event sourcing hjælper med at opnå høj skriveydelse ved at tilføje begivenhederne og undgå opdateringer og sletninger af eksisterende begivenheder.

Lad os nu se på vores vedvarende enhed i hilsen-impl-projektet, HilsenEnhed:

offentlig klasse GreetingEntity udvider PersistentEntity {@ Override public Adfærd initialBehavior (Valgfri snapshotState) {BehaviorBuilder b = newBehaviorBuilder (ny GreetingState ("Hej")); b.setCommandHandler (ReceiveGreetingCommand.class, (cmd, ctx) -> {String fromUser = cmd.getFromUser (); String currentGreeting = state (). getMessage (); return ctx.thenPersist (new ReceiveGreetingEvent (fromUser), evt -> ctx.reply (currentGreeting + fromUser + "!");}); b.setEventHandler (ReceiveGreetingEvent.class, evt -> state (). withMessage ("Hej igen")); returnere b.build (); }}

Lagom giver Vedvarende enhed API til behandling af indkommende begivenheder af typen Kommando via setCommandHandler () metoder og vedvarende tilstandsændringer som hændelser af typen Begivenhed. Domæneobjekttilstanden opdateres ved at anvende begivenheden i den aktuelle tilstand ved hjælp af setEventHandler () metode. Den oprindelige adfærd () abstrakt metode definerer Opførsel af enheden.

I initialBehavior (), vi bygger original Hilsenstat "Hej" tekst. Så kan vi definere en ModtagetGreetingCommand kommandobehandler - som producerer en ModtagetGreetingEvent Begivenhed og bliver vedvarende i hændelsesloggen.

HilsenStat genberegnes til "Hej igen" af ModtagetGreetingEvent begivenhedshåndteringsmetode. Som nævnt tidligere påkalder vi ikke settere - i stedet opretter vi en ny forekomst af Stat fra den aktuelle begivenhed, der behandles.

Lagom følger konventionen om HilsenKommando og Hilsen Begivenhed grænseflader til at holde alle de understøttede kommandoer og begivenheder sammen:

offentlig grænseflade GreetingCommand udvider Jsonable {@JsonDeserialize offentlig klasse ReceiveGreetingCommand implementerer GreetingCommand, CompressedJsonable, PersistentEntity.ReplyType {@JsonCreator public ReceiveGreetingCommand (String fromUser) {this.fromUser = Preconditions.checkNotNull (fra User) }}}
offentlig grænseflade GreetingEvent udvider Jsonable {class ReceiveGreetingEvent implementerer GreetingEvent {@JsonCreator public ReceiveGreetingEvent (String fromUser) {this.fromUser = fromUser; }}}

7. Serviceimplementering

7.1. Hilsen service

offentlig klasse GreetingServiceImpl implementerer GreetingService {@Inject public GreetingServiceImpl (PersistentEntityRegistry persistentEntityRegistry, WeatherService weatherService) {this.persistentEntityRegistry = persistentEntityRegistry; this.weatherService = weatherService; persistentEntityRegistry.register (GreetingEntity.class); } @Override public ServiceCall handleGreetFrom (String user) {return request -> {PersistentEntityRef ref = persistentEntityRegistry.refFor (GreetingEntity.class, user); CompletableFuture greetingResponse = ref.ask (ny ReceiveGreetingCommand (bruger)) .toCompletableFuture (); CompletableFuture todaysWeatherInfo = (CompletableFuture) weatherService .weatherStatsForToday (). Påkalde (); prøv {return CompletableFuture.completedFuture (greetingResponse.get () + "Dagens vejrstatistik:" + todaysWeatherInfo.get (). getMessage ()); } fange (InterruptedException | ExecutionException e) {return CompletableFuture.completedFuture ("Beklager nogle fejl i vores ende, arbejder på det"); }}; }}

Kort sagt, vi injicerer PersistentEntityRegistry og WeatherService afhængigheder ved hjælp af @Indsprøjte (leveret af Guice framework), og vi registrerer den vedvarende HilsenEnhed.

Det handleGreetFrom () implementering sender ModtagetGreetingCommand til HilsenEnhed til at behandle og returnere hilsenstrengen asynkront ved hjælp af Fuldført gennemførelse af FuldførelseStage API.

På samme måde foretager vi et asynkroniseret opkald til Vejr mikroservice for at hente vejrstatistikker i dag.

Endelig sammenkæder vi begge output og returnerer det endelige resultat til brugeren.

At registrere en implementering af servicebeskrivelsesgrænsefladen HilsenService med Lagom, lad os skabe GreetingServiceModule klasse, der strækker sig Abstrakt modul og redskaber ServiceGuiceSupport:

offentlig klasse GreetingServiceModule udvider AbstractModule implementerer ServiceGuiceSupport {@Override beskyttet ugyldig konfigurere () {bindServices (serviceBinding (GreetingService.class, GreetingServiceImpl.class)); bindClient (WeatherService.class); }} 

Også Lagom bruger internt Play Framework. Og så kan vi tilføje vores modul til Play's liste over aktiverede moduler i src / main / resources / application.conf fil:

play.modules.enabled + = com.baeldung.lagom.helloworld.greeting.impl.GreetingServiceModule

7.2. Vejr Service

Efter at have set på HilsenServiceImpl, WeatherServiceImpl er ret ligetil og selvforklarende:

offentlig klasse WeatherServiceImpl implementerer WeatherService {@Override public ServiceCall weatherStatsForToday () {return req -> CompletableFuture.completedFuture (WeatherStats.forToday ()); }}

Vi følger de samme trin som vi gjorde ovenfor for hilsen til at registrere vejrmodulet hos Lagom:

offentlig klasse WeatherServiceModule udvider AbstractModule implementerer ServiceGuiceSupport {@Override beskyttet ugyldig konfiguration () {bindServices (serviceBinding (WeatherService.class, WeatherServiceImpl.class)); }}

Registrer også vejrmodulet på Play's rammeliste over aktiverede moduler:

play.modules.enabled + = com.baeldung.lagom.helloworld.weather.impl.WeatherServiceModule

8. Kørsel af projektet

Lagom tillader det kører et vilkårligt antal tjenester sammen med en enkelt kommando.

Vi kan starte vores projekt ved at trykke på nedenstående kommando:

sbt lagom: runAll

Dette starter den integrerede Servicelokator, indlejret Cassandra og start derefter mikrotjenester parallelt. Den samme kommando genindlæser også vores individuelle mikroservice, når koden ændres, så vi behøver ikke at genstarte dem manuelt.

Vi kan fokusere på vores logik og Lagom håndterer kompilering og genindlæsning. Når det er startet med succes, ser vi følgende output:

................ [info] Cassandra-server kører ved 127.0.0.1:4000 [info] Servicelokator kører på // localhost: 8000 [info] Servicegateway kører på / / localhost: 9000 [info] Service weather-impl lytter efter HTTP på 0: 0: 0: 0: 0: 0: 0: 0: 56231 og hvordan tjenesterne interagerer via [info] Servicehilsen-impl lytter til HTTP på 0 : 0: 0: 0: 0: 0: 0: 0: 49356 [info] (Services startet, tryk på enter for at stoppe og gå tilbage til konsollen ...)

Når vi er startet med succes, kan vi lave en krølleanmodning om hilsen:

krølle // localhost: 9000 / api / hilsen / Amit

Vi ser følgende output på konsollen:

Hej Amit! Dagens vejrstatistik: Gå til regn, tag paraply

Kørsel af samme krølleanmodning for en eksisterende bruger ændrer hilsen:

Hej igen Amit! Dagens vejrstatistik: Gå til regn, tag paraply

9. Konklusion

I denne artikel har vi dækket, hvordan man bruger Lagom framework til at oprette to mikrotjenester, der interagerer asynkront.

Den komplette kildekode og alle kodestykker til denne artikel er tilgængelige i GitHub-projektet.


$config[zx-auto] not found$config[zx-overlay] not found