Sprievodca reaktívnymi mikroslužbami pomocou Lagom Framework

1. Prehľad

V tomto článku preskúmame rámec Lagom a implementovať ukážkovú aplikáciu pomocou architektúry riadenej reaktívnymi mikroslužbami.

Jednoducho povedané, reaktívne softvérové ​​aplikácie sa spoliehajú na asynchrónnu komunikáciu riadenú správami a sú vysoko Reagovať, Odolný a Elastické v prírode.

Pod architektúrou riadenou mikroslužbami sme mysleli rozdelenie systému na hranice medzi kolaboratívnymi službami na dosiahnutie cieľov Izolácia, Autonómia, Jednotná zodpovednosť, Mobilita, atď. Ďalšie informácie o týchto dvoch konceptoch nájdete v dokumente Reaktívny manifest a Architektúra reaktívnych mikroslužieb.

2. Prečo Lagom?

Lagom je rámec otvoreného zdroja zostavený s ohľadom na prechod od monolitov k aplikačnej architektúre riadenej mikroslužbami. Abstrahuje zložitosť budovania, chodu a monitorovania aplikácií poháňaných mikroslužbami.

V zákulisí rámec Lagom využíva Play Framework, runtime riadený správami Akka, Kafka na oddelenie služieb, Event Sourcing a CQRS vzory a podporu ConductR pre monitorovanie a škálovanie mikroslužieb v prostredí kontajnera.

3. Hello World in Lagom

Vytvárame aplikáciu Lagom na spracovanie žiadosti o pozdrav od používateľa a na odpoveď s uvítacou správou spolu so štatistikami počasia pre daný deň.

A budeme vyvíjať dve samostatné mikroslužby: Pozdravujem vás a Počasie.

Pozdravujem vás sa zameria na vybavenie žiadosti o pozdrav, interakciu s meteorologickou službou s cieľom odpovedať späť používateľovi. The Počasie mikroslužba bude pre dnešok vybavovať požiadavky na štatistiku počasia.

V prípade interakcie existujúceho používateľa s Pozdravujem vás mikroslužby, používateľovi sa zobrazí iná uvítacia správa.

3.1. Predpoklady

  1. Inštalácia Scala (momentálne používame verziu 2.11.8) odtiaľto
  2. Inštalácia sbt nástroj na vytváranie (momentálne používame 0.13.11) odtiaľto

4. Nastavenie projektu

Poďme sa teraz rýchlo pozrieť na kroky na nastavenie funkčného systému Lagom.

4.1. Budovanie SBT

Vytvorte priečinok projektu lagom-ahoj-svet za ktorým nasleduje zostavovací súborbuild.sbt. Systém Lagom sa zvyčajne skladá zo súboru sbt zostavuje s každým zostavením zodpovedajúcim skupine súvisiacich služieb:

organizácia v ThisBuild: = "com.baeldung" scalaVersion v ThisBuild: = "2.11.8" lagomKafkaEnabled v ThisBuild: = false lazy val pozdravApi = projekt ("pozdrav-api"). nastavenia (verzia: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslApi)) lenivý val pozdravImpl = projekt ("pozdrav-impl") .enablePlugins (LagomJava) .settings (verzia: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslPersistenceCassandra)). greetingApi, weatherApi) lazy val weatherApi = project ("weather-api") .settings (version: = "1.0-SNAPSHOT", libraryDependencies ++ = Seq (lagomJavadslApi)) lazy val weatherImpl = project ("weather-impl"). enablePlugins (LagomJava) .settings (verzia: = "1.0-SNAPSHOT") .dependsOn (weatherApi) def project (id: String) = Project (id, base = file (id))

Najprv sme zadali podrobnosti organizácie, scala verzia a vypnutá Kafka pre aktuálny projekt. Lagom sa riadi konvenciou dvoch samostatných projektov pre každú mikroslužbu: Projekt API a implementačný projekt.

Projekt API obsahuje servisné rozhranie, od ktorého závisí implementácia.

Pridali sme závislosti do príslušných modulov Lagom ako lagomJavadslApi, lagomJavadslPersistenceCassandra za používanie Lagom Java API v našich mikroslužbách a ukladanie udalostí súvisiacich s perzistentnou entitou v Cassandra, resp.

Tiež pozdrav-impl projekt závisí od počasie-api projekt na získanie a poskytnutie štatistík o počasí počas pozdravu používateľa.

Podpora pre doplnok Lagom sa pridáva vytvorením priečinka doplnku s pluginy.sbt pilník, ktorý má položku pre plugin Lagom. Poskytuje všetku potrebnú podporu pre zostavenie, spustenie a nasadenie našej aplikácie.

Tiež sbteclipse plugin bude užitočný, ak pre tento projekt použijeme Eclipse IDE. Nasledujúci kód zobrazuje obsah oboch doplnkov:

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

Vytvoriť project / build.properties súbor a upresniť sbt verzia na použitie:

sbt.verzia = 0.13.11

4.2. Generovanie projektu

Beží sbt príkaz z koreňa projektu vygeneruje nasledujúce šablóny projektu:

  1. pozdrav-api
  2. pozdrav-impl
  3. počasie-api
  4. počasie-impl

Predtým, ako začneme implementovať mikroslužby, pridajme src / main / java a src / main / java / resources priečinky vo vnútri každého z projektov, aby ste sledovali usporiadanie adresárov projektu podobné Mavenovi.

Vo vnútri sú tiež generované dva dynamické projekty root-project / target / lagom-dynamic-projects:

  1. lagom-internal-meta-project-cassandra
  2. vyhľadávací modul lagom-internal-meta-project-service-locator

Tieto projekty využíva spoločnosť Lagom interne.

5. Servisné rozhranie

V pozdrav-api zadáme nasledujúce rozhranie:

verejné rozhranie GreetingService rozširuje službu {public ServiceCall handleGreetFrom (používateľ reťazca); @Override default Descriptor descriptor () {návrat s názvom ("greetingservice") .withCalls (restCall (Method.GET, "/ api / pozdrav /: fromUser", toto :: handleGreetFrom)) .withAutoAcl (true); }}

Pozdravná služba vystavuje handleGreetFrom () na vybavenie pozdravu od používateľa. A ServiceCall Ako návratový typ týchto metód sa používa API. ServiceCall trvá dva parametre typu Žiadosť a Odozva.

The Žiadosť parameter je typ prichádzajúcej správy s požiadavkou a Odozva parameter je typ odchádzajúcej správy s odpoveďou.

V príklade vyššie nepoužívame užitočné zaťaženie žiadosti, typ žiadosti je Nepoužitéa Odozva typ je a String pozdravnú správu.

Pozdravná služba tiež špecifikuje mapovanie na skutočnú prepravu použitú počas vyvolania poskytnutím predvolenej implementácie Service.descriptor () metóda. Služba s názvom pozdravná služba sa vracia.

handleGreetFrom () servisné volanie je mapované pomocou identifikátora odpočinku: ZÍSKAJTE typ metódy a identifikátor cesty / api / pozdrav /: od používateľa mapované na handleGreetFrom () metóda. Ak sa chcete dozvedieť viac podrobností o identifikátoroch služieb, pozrite si tento odkaz.

Na tých istých riadkoch definujeme WeatherService rozhranie v počasie-api projekt. weatherStatsForToday () metóda a deskriptor () metóda je do veľkej miery samozrejmá:

verejné rozhranie WeatherService rozširuje službu {public ServiceCall weatherStatsForToday (); @Override default Descriptor descriptor () {návrat s názvom ("weatherservice") .withCalls (restCall (Method.GET, "/ api / počasie", toto :: weatherStatsForToday)) .withAutoAcl (true); }};

WeatherStats je definované ako výčet so vzorovými hodnotami pre rôzne počasie a náhodným vyhľadávaním, aby sa vrátila predpoveď počasia na daný deň:

verejné enum WeatherStats {STATS_RAINY ("Chystáte sa pršať, vezmite si dáždnik"), STATS_HUMID ("Chystáte sa veľmi vlhký, vezmite si vodu"); public static WeatherStats forToday () {return VALUES.get (RANDOM.nextInt (SIZE)); }}

6. Lagom Persistence - sourcing udalostí

Jednoducho povedané, v systéme využívajúcom Sourcing udalostí, budeme schopní zachytiť všetky zmeny ako nemenné udalosti domény pripojené jeden po druhom. Aktuálny stav sa odvodzuje prehraním a spracovaním udalostí. Táto operácia je v podstate a foldLeft operácia známa z paradigmy funkčného programovania.

Zdroj udalostí pomáha dosiahnuť vysoký výkon zápisu pripojením udalostí a vyhýbaním sa aktualizáciám a výmazom existujúcich udalostí.

Pozrime sa teraz na našu pretrvávajúcu entitu v projekte pozdrav-impl, GreetingEntity:

public class GreetingEntity extends PersistentEntity {@Override public Behavior initialBehavior (Optional snapshotState) {BehaviorBuilder b = newBehaviorBuilder (new GreetingState ("Hello")); b.setCommandHandler (ReceivedGreetingCommand.class, (cmd, ctx) -> {String fromUser = cmd.getFromUser (); String currentGreeting = state (). getMessage (); return ctx.thenPersist (new ReceivedGreetingEvent (fromUser), evt -> ctx.reply (currentGreeting + fromUser + "!"));}); b.setEventHandler (ReceivedGreetingEvent.class, evt -> state (). withMessage ("Hello Again")); návrat b.build (); }}

Lagom poskytuje PersistentEntity API na spracovanie prichádzajúcich udalostí typu Velenie cez setCommandHandler () metódy a pretrvávajú zmeny stavu ako udalosti typu Udalosť. Stav objektu domény sa aktualizuje použitím udalosti na aktuálny stav pomocou znaku setEventHandler () metóda. The initialBehavior () abstraktná metóda definuje Správanie subjektu.

V initialBehavior (), staviame originál Pozdravný štát „Dobrý deň“. Potom môžeme definovať a Prijatý pozdrav obsluha príkazov - ktorá produkuje a ReceivedGreetingEvent Udalosť a pretrváva v denníku udalostí.

Pozdravný štát je prepočítaný na „Ahoj znova“ ReceivedGreetingEvent metóda obsluhy udalosti. Ako už bolo spomenuté, nevyvolávame nastavovače - namiesto toho vytvárame novú inštanciu Štát od práve prebiehajúcej udalosti.

Lagom sa riadi dohovorom z GreetingCommand a PozdravEvent rozhrania na uchovávanie všetkých podporovaných príkazov a udalostí:

verejné rozhranie GreetingCommand rozširuje Jsonable {@JsonDeserialize verejnú triedu ReceivedGreetingCommand implementuje GreetingCommand, CompressedJsonable, PersistentEntity.ReplyType {@JsonCreator public ReceivedGreetingCommand (String fromUser) {this.fromUser = Preconditions.checkNot }}}
verejné rozhranie GreetingEvent rozširuje Jsonable {class ReceivedGreetingEvent implementuje GreetingEvent {@JsonCreator public ReceivedGreetingEvent (String fromUser) {this.fromUser = fromUser; }}}

7. Implementácia služby

7.1. Pozdravná služba

verejná trieda GreetingServiceImpl implementuje GreetingService {@Inject public GreetingServiceImpl (PersistentEntityRegistry persistentEntityRegistry, WeatherService weatherService) {this.persistentEntityRegistry = persistentEntityRegistry; this.weatherService = weatherService; persistentEntityRegistry.register (GreetingEntity.class); } @Override public ServiceCall handleGreetFrom (užívateľ reťazca) {požiadavka na vrátenie -> {PersistentEntityRef ref = persistentEntityRegistry.refFor (GreetingEntity.class, užívateľ); CompletableFuture greetingResponse = ref.ask (nový ReceivedGreetingCommand (užívateľ)) .toCompletableFuture (); CompletableFuture todaysWeatherInfo = (CompletableFuture) weatherService .weatherStatsForToday (). Invoke (); try {return CompletableFuture.completedFuture (greetingResponse.get () + "Dnešné štatistiky počasia:" + todaysWeatherInfo.get (). getMessage ()); } catch (InterruptedException | ExecutionException e) {return CompletableFuture.completedFuture ("Prepáčte, na našom konci je chyba, pracujeme na tom"); }}; }}

Jednoducho povedané, vstrekneme PersistentEntityRegistry a WeatherService závislosti pomocou @Inject (poskytuje Guice rámec), a zaregistrujeme perzistentné GreetingEntity.

The handleGreetFrom () implementácia je odosielanie Prijatý pozdrav do GreetingEntity spracovať a vrátiť pozdravný reťazec asynchrónne pomocou CompletableFuture implementácia DokončenieStage API.

Podobne uskutočňujeme asynchronné volanie na číslo Počasie mikroslužba na získanie štatistík počasia pre dnešok.

Nakoniec obidva výstupy zreťazíme a konečný výsledok vrátime používateľovi.

Zaregistrovať implementáciu rozhrania deskriptora služby Pozdravná služba s Lagom, poďme vytvárať GreetingServiceModule trieda, ktorá sa rozširuje Abstraktný modul a náradie ServiceGuiceSupport:

public class GreetingServiceModule extends AbstractModule implements ServiceGuiceSupport {@Override protected void configure () {bindServices (serviceBinding (GreetingService.class, GreetingServiceImpl.class)); bindClient (WeatherService.class); }} 

Spoločnosť Lagom tiež interne používa rámec Play. Takže môžeme náš modul pridať do zoznamu povolených modulov Play v zozname src / main / resources / application.conf spis:

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

7.2. Meteorologická služba

Po prezretí GreetingServiceImpl, WeatherServiceImpl je do značnej miery priamy a samozrejmý:

verejná trieda WeatherServiceImpl implementuje WeatherService {@Override public ServiceCall weatherStatsForToday () {return req -> CompletableFuture.completedFuture (WeatherStats.forToday ()); }}

Pri registrácii modulu počasia s Lagom postupujeme podľa rovnakých krokov ako v prípade modulu pozdrav:

public class WeatherServiceModule extends AbstractModule implements ServiceGuiceSupport {@Override protected void configure () {bindServices (serviceBinding (WeatherService.class, WeatherServiceImpl.class)); }}

Zaregistrujte tiež modul počasia do zoznamu povolených modulov Play:

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

8. Spustenie projektu

Lagom umožňuje spustenie ľubovoľného počtu služieb spolu s jediným príkazom.

Náš projekt môžeme spustiť stlačením nasledujúceho príkazu:

sbt lagom: runAll

Týmto sa spustí vložený Vyhľadávač služieb, vložené Cassandra a potom paralelne spustite mikroslužby. Rovnaký príkaz znova načíta našu individuálnu mikroslužbu, keď sa kód zmení, takže my nemusíte ich reštartovať manuálne.

Môžeme sa sústrediť na našu logiku a Lagom zvládne kompiláciu a opätovné načítanie. Po úspešnom spustení sa zobrazí nasledujúci výstup:

................ [info] Server Cassandra bežiaci na 127.0.0.1:4000 [info] Vyhľadávač služieb je spustený na // localhost: 8000 [info] Servisná brána beží na / / localhost: 9000 [info] Počúvanie služby impl. počasia pre HTTP na 0: 0: 0: 0: 0: 0: 0: 0: 56231 a ako služby interagujú prostredníctvom [info] Služby pozdrav-impl počúvanie pre HTTP na 0 : 0: 0: 0: 0: 0: 0: 0: 49356 [info] (Služby spustené, stlačením klávesu Enter zastavíte a vrátite sa na konzolu ...)

Po úspešnom začatí môžeme požiadať o zvlnenie na pozdrav:

zvlnenie // localhost: 9000 / api / pozdrav / Amit

Na konzole uvidíme nasledujúci výstup:

Ahoj Amit! Dnešné štatistiky počasia: Going to Rain, Take Umbrella

Spustenie rovnakej žiadosti o zvlnenie pre existujúceho používateľa zmení uvítaciu správu:

Ahoj ešte raz Amit! Dnešné štatistiky počasia: Going to Rain, Take Umbrella

9. Záver

V tomto článku sme sa zaoberali tým, ako používať rámec Lagom na vytvorenie dvoch mikroslužieb, ktoré interagujú asynchrónne.

Kompletný zdrojový kód a všetky útržky kódu pre tento článok sú k dispozícii v projekte GitHub.


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