Veiledning til reaktive mikrotjenester ved bruk av Lagom Framework

1. Oversikt

I denne artikkelen vil vi utforske Lagom-rammeverket og implementere et eksempel på en applikasjon ved hjelp av en reaktiv mikrotjenestedrevet arkitektur.

Enkelt sagt, reaktive applikasjoner er avhengige av meldingsdrevet asynkron kommunikasjon og er i høyeste grad Mottakelig, Fleksibel og Elastisk i naturen.

Med mikroservicedrevet arkitektur mente vi å dele systemet i grenser mellom samarbeidstjenester for å oppnå mål om Isolering, Autonomi, Enkelt ansvar, Mobilitetosv. For ytterligere lesing om disse to konseptene, se The Reactive Manifesto and Reactive Microservices Architecture.

2. Hvorfor Lagom?

Lagom er et open source-rammeverk bygget med tanke på å skifte fra monolitter til mikrotjenester-drevet applikasjonsarkitektur. Den abstrakte kompleksiteten i å bygge, kjøre og overvåke applikasjoner som drives av mikrotjenester.

Bak kulissene bruker Lagom framework Play Framework, en Akka-meldingsdrevet kjøretid, Kafka for avkoblingstjenester, Event Sourcing og CQRS-mønstre, og ConductR-støtte for overvåking og skalering av mikrotjenester i containermiljøet.

3. Hello World i Lagom

Vi oppretter et Lagom-program for å håndtere en hilsenforespørsel fra brukeren og svare tilbake med en hilsenmelding sammen med værstatistikk for dagen.

Og vi skal utvikle to separate mikrotjenester: Hilsen og Vær.

Hilsen vil fokusere på å håndtere en hilsenforespørsel, samhandle med værservice for å svare tilbake til brukeren. De Vær microservice vil betjene forespørselen om værstatistikk for i dag.

I tilfelle eksisterende bruker samhandler med Hilsen mikroservice, vil den forskjellige hilsen vises til brukeren.

3.1. Forutsetninger

  1. Installere Scala (vi bruker for øyeblikket 2.11.8 versjon) herfra
  2. Installere sbt byggeverktøy (vi bruker for øyeblikket 0.13.11) herfra

4. Prosjektoppsett

La oss nå se raskt på trinnene for å sette opp et fungerende Lagom-system.

4.1. SBT Build

Lag en prosjektmappe lagom-hei-verden etterfulgt av build-filenbuild.sbt. Et Lagom-system består vanligvis av et sett med sbt bygger med hver bygg som tilsvarer en gruppe relaterte tjenester:

organisasjon i ThisBuild: = "com.baeldung" scalaVersion i ThisBuild: = "2.11.8" lagomKafkaEnabled i ThisBuild: = falske lazy val greetingApi = prosjekt ("hilsen-api") .settings (versjon: = "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) lat val weatherApi = prosjekt ("weather-api") .settings (versjon: = "1.0-SNAPSHOT", bibliotekavhengighet ++ = Seq (lagomJavadslApi)) lat val weatherImpl = prosjekt ("weather-impl"). enablePlugins (LagomJava) .settings (versjon: = "1.0-SNAPSHOT") .dependsOn (weatherApi) def prosjekt (id: String) = Prosjekt (id, base = fil (id))

Til å begynne med har vi spesifisert organisasjonsdetaljene, scala versjon, og deaktivert Kafka for det aktuelle prosjektet. Lagom følger en konvensjon med to separate prosjekter for hver mikrotjeneste: API-prosjekt og et implementeringsprosjekt.

API-prosjektet inneholder tjenestegrensesnittet som implementeringen avhenger av.

Vi har lagt til avhengigheter til de aktuelle Lagom-modulene som lagomJavadslApi, lagomJavadslPersistenceCassandra for å bruke Lagom Java API i våre mikrotjenester og lagre hendelser relatert til den vedvarende enheten i Cassandra, henholdsvis.

Også, den hilsen-impl prosjektet avhenger av vær-api prosjekt for å hente og servere værstatistikk mens du hilser på en bruker.

Støtte for Lagom-pluginet legges til ved å opprette en plugin-mappe med plugins.sbt fil, har en oppføring for Lagom-plugin. Den gir all nødvendig støtte for å bygge, kjøre og distribuere applikasjonen vår.

Også, den sbteclipse plugin vil være nyttig hvis vi bruker Eclipse IDE for dette prosjektet. Koden nedenfor viser innholdet for begge plugins:

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

Skape prosjekt / build.properties fil og spesifiser sbt versjon å bruke:

sbt.versjon = 0.13.11

4.2. Prosjektgenerering

Løping sbt kommando fra prosjektroten vil generere følgende prosjektmaler:

  1. hilsen-api
  2. hilsen-impl
  3. vær-api
  4. vær-impl

Før vi begynner å implementere mikrotjenestene, la oss legge til src / main / java og src / main / java / resources mapper inne i hvert av prosjektene, for å følge Maven-lignende prosjektkatalogoppsett.

Det genereres også to dynamiske prosjekter inne prosjekt-rot / mål / lagom-dynamisk-prosjekter:

  1. lagom-internal-meta-project-cassandra
  2. lagom-internal-meta-project-service-locator

Disse prosjektene brukes internt av Lagom.

5. Service-grensesnitt

I hilsen-api prosjekt spesifiserer vi følgende grensesnitt:

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

HilsenService avslører handleGreetFrom () for å håndtere hilsen fra brukeren. EN ServiceCall API brukes som returtype for disse metodene. ServiceCall tar to typeparametere Be om og Respons.

De Be om parameter er typen innkommende forespørselsmelding, og Respons parameteren er typen utgående svarmelding.

I eksemplet ovenfor bruker vi ikke nyttelast for forespørsel, forespørselstypen er Ikke brukt, og Respons typen er en String hilsen.

HilsenService spesifiserer også en kartlegging til den faktiske transporten som ble brukt under påkallingen, ved å gi en standardimplementering av Service.descriptor () metode. En tjeneste som heter hilsen service blir returnert.

handleGreetFrom () tjenesteanropet er kartlagt ved hjelp av en hvile-id: metodetype og baneidentifikator / api / hilsen /: fra bruker kartlagt til handleGreetFrom () metode. Sjekk denne lenken for mer informasjon om tjenesteidentifikatorer.

På de samme linjene definerer vi WeatherService grensesnitt i vær-api prosjekt. weatherStatsForToday () metode og deskriptor () metoden er ganske mye selvforklarende:

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

WeatherStats er definert som en enum med prøveverdier for forskjellige vær og tilfeldig oppslag for å returnere værmelding for dagen:

offentlig enum WeatherStats {STATS_RAINY ("Gå til regn, ta paraply"), STATS_HUMID ("Blir veldig fuktig, ta vann"); offentlig statisk WeatherStats forToday () {return VALUES.get (RANDOM.nextInt (SIZE)); }}

6. Lagom Persistence - Arrangement av hendelser

Enkelt sagt, i et system som bruker Arrangementssourcing, vil vi være i stand til å fange opp alle endringene som uforanderlige domenehendelser lagt ved hverandre. Den nåværende tilstanden er avledet ved å spille av og behandle hendelser. Denne operasjonen er egentlig en foldLeft operasjon kjent fra Functional Programming paradigm.

Arrangementssourcing hjelper til med å oppnå høy skriveytelse ved å legge til hendelsene og unngå oppdateringer og slettinger av eksisterende hendelser.

La oss nå se på vår vedvarende enhet i hilsen-impl-prosjektet, HilsenEnhet:

offentlig klasse GreetingEntity utvider PersistentEntity {@Override public Behavior initialBehavior (Valgfritt snapshotState) {BehaviorBuilder b = newBehaviorBuilder (new GreetingState ("Hello")); b.setCommandHandler (ReceiveGreetingCommand.class, (cmd, ctx) -> {String fromUser = cmd.getFromUser (); String currentGreeting = state (). getMessage (); return ctx.thenPersist (new ReceiveGreetingEvent (fromUser), evt -> ctx.reply (gjeldende hilsen + fra bruker + "!"))}}); b.setEventHandler (ReceiveGreetingEvent.class, evt -> state (). withMessage ("Hello Again")); returnere b.build (); }}

Lagom gir Vedvarende enhet API for behandling av innkommende hendelser av typen Kommando via setCommandHandler () metoder og vedvarer tilstandsendringer som hendelser av typen Begivenhet. Domenenes objekttilstand oppdateres ved å bruke hendelsen til gjeldende tilstand ved hjelp av setEventHandler () metode. Den opprinnelige oppførselen () abstrakt metode definerer Oppførsel av enheten.

I initialBehavior (), vi bygger original Hilsenstat "Hei" -tekst. Da kan vi definere en Mottatt hilsen-kommando kommandobehandler - som produserer en Mottatt hilsen hendelse Hendelse og blir vedvarende i hendelsesloggen.

Hilsenstat blir beregnet på nytt til "Hello Again" av Mottatt hilsen hendelse hendelsesbehandlingsmetode. Som nevnt tidligere påkaller vi ikke settere - i stedet lager vi en ny forekomst av Stat fra den aktuelle hendelsen som behandles.

Lagom følger konvensjonen om HilsenKommando og HilsenEvent grensesnitt for å holde sammen alle støttede kommandoer og hendelser:

offentlig grensesnitt GreetingCommand utvider Jsonable {@JsonDeserialize offentlig klasse ReceiveGreetingCommand implementerer GreetingCommand, CompressedJsonable, PersistentEntity.ReplyType {@JsonCreator public ReceiveGreetingCommand (String fromUser) {this.fromUser = Preconditions.checkNotNull (fromUser) " }}}
offentlig grensesnitt GreetingEvent utvider Jsonable {class ReceiveGreetingEvent implementerer GreetingEvent {@JsonCreator public ReceiveGreetingEvent (String fromUser) {this.fromUser = fromUser; }}}

7. Tjenesteimplementering

7.1. Hilsen

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 (bruker)) .toCompletableFuture (); CompletableFuture todaysWeatherInfo = (CompletableFuture) weatherService .weatherStatsForToday (). Påkalle (); prøv {return CompletableFuture.completedFuture (greetingResponse.get () + "Dagens værstatistikk:" + todaysWeatherInfo.get (). getMessage ()); } fange (InterruptedException | ExecutionException e) {return CompletableFuture.completedFuture ("Beklager noen feil på slutten, jobber med det"); }}; }}

Enkelt sagt, vi injiserer PersistentEntityRegistry og WeatherService avhengigheter ved hjelp @Injiser (levert av Guice rammeverk), og vi registrerer den vedvarende HilsenEnhet.

De handleGreetFrom () implementering er å sende Mottatt hilsen-kommando til HilsenEnhet å behandle og returnere hilsenstrengen asynkront ved hjelp av Fullførbar fremtid Implementering av CompletionStage API.

Tilsvarende ringer vi til asynkronisering til Vær mikroservice for å hente værstatistikk for i dag.

Til slutt sammenkobler vi begge utgangene og returnerer det endelige resultatet til brukeren.

For å registrere en implementering av tjenestebeskrivelsesgrensesnittet HilsenService med Lagom, la oss lage GreetingServiceModule klasse som strekker seg Abstrakt modul og redskaper ServiceGuiceSupport:

offentlig klasse GreetingServiceModule utvider AbstractModule implementerer ServiceGuiceSupport {@ Override-beskyttet tom konfigurering () {bindServices (serviceBinding (GreetingService.class, GreetingServiceImpl.class)); bindClient (WeatherService.class); }} 

Lagom bruker også Play Framework internt. Og så kan vi legge til modulen vår i Play liste over aktiverte moduler i src / main / resources / application.conf fil:

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

7.2. Væretjeneste

Etter å ha sett på HilsenServiceImpl, WeatherServiceImpl er ganske grei og selvforklarende:

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

Vi følger de samme trinnene som vi gjorde ovenfor for hilsenmodulen for å registrere værmodulen hos Lagom:

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

Registrer også værmodulen på Play rammeliste over aktiverte moduler:

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

8. Kjører prosjektet

Lagom tillater kjører et hvilket som helst antall tjenester sammen med en enkelt kommando.

Vi kan starte prosjektet vårt ved å trykke kommandoen nedenfor:

sbt lagom: runAll

Dette starter den innebygde Service Locator, en del av Cassandra og start deretter mikrotjenester parallelt. Den samme kommandoen laster også inn vår individuelle mikrotjeneste når koden endres slik at vi trenger ikke å starte dem på nytt manuelt.

Vi kan fokusere på logikken vår og Lagom håndterer samlingen og omlastingen. Når du har startet med suksess, ser vi følgende utdata:

................ [info] Cassandra-serveren kjører på 127.0.0.1:4000 [info] Tjenestelokatoren kjører på // localhost: 8000 [info] Tjenestegatewayen kjører på / / localhost: 9000 [info] Service weather-impl lytter etter HTTP på 0: 0: 0: 0: 0: 0: 0: 0: 56231 og hvordan tjenestene samhandler via [info] Service greeting-impl lytter etter HTTP på 0 : 0: 0: 0: 0: 0: 0: 0: 49356 [info] (Tjenestene startet, trykk enter for å stoppe og gå tilbake til konsollen ...)

Når du har startet med suksess, kan vi be om en hilsen for krølling:

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

Vi ser følgende utdata på konsollen:

Hei Amit! Dagens værstatistikk: Gå til regn, ta paraply

Å kjøre den samme krøllforespørselen for en eksisterende bruker vil endre hilsen:

Hei igjen Amit! Dagens værstatistikk: Gå til regn, ta paraply

9. Konklusjon

I denne artikkelen har vi dekket hvordan du bruker Lagom framework til å lage to mikrotjenester som samhandler asynkront.

Den komplette kildekoden og alle kodebiter for denne artikkelen er tilgjengelig i GitHub-prosjektet.


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