I denne enkle vejledning vil vi oprette et par mikrotjenester på Spring Boot og organisere interaktionen mellem dem via Axon-frameworket.

Lad os sige, at vi har denne opgave.
Der er en kilde til aktiemarkedstransaktioner. Denne kilde sender os transaktioner via Rest-grænsefladen.
Vi skal modtage disse transaktioner, gemme dem i en database og oprette en praktisk lagring i hukommelsen.
Denne lagring skal udføre følgende funktioner:
- returnere en liste over handler;
- returner den fulde position, dvs. tabel "instrument" - "aktuelt antal papirer";
- returnere positionen for et givet instrument.
Hvordan griber vi denne opgave an?
I henhold til principperne for microservice-mode skal vi opdele opgaven i bestanddele af microservices:
- modtagelse af en transaktion fra Rest;
- gemmer transaktionen i databasen;
- lagring i hukommelsen til repræsentation af positionsdata.
Lad os lave den første og tredje service inden for rammerne af denne vejledning, og lad den anden være til anden del (skriv i kommentarerne, hvis du er interesseret).
Så vi har to mikrotjenester.
Den første modtager data udefra.
Den anden behandler disse data og svarer på indgående anmodninger.
Selvfølgelig ønsker vi at få horisontal skalering, uafbrudte opdateringer og andre fordele ved mikrotjenester.
Hvad er den meget vanskelige opgave, vi står over for?
Der er faktisk mange af dem, men lad os nu tale om, hvordan data vil flyde mellem disse mikrotjenester. Du kan også lave en pause mellem dem, du kan oprette en slags kø, du kan finde på en masse ting med deres egne fordele og ulemper.
Lad os overveje én mulig tilgang - asynkron interaktion via Axon-rammeværk.
Hvad er fordelene ved denne løsning?
For det første øger asynkron interaktion fleksibiliteten (ja, der er en ulempe her, men for nu taler vi kun om fordelene).
For det andet får vi lige ud af æsken Event sourcing и CQRS.
For det tredje leverer Axon en færdiglavet infrastruktur, og vi behøver kun at fokusere på at udvikle forretningslogik.
Lad os komme igang.
Vores projekt vil være i gradvis fremgang. Den vil have tre moduler:
- fælles. modul med almindelige datastrukturer (vi kan ikke lide kopier-indsæt);
- tradeCreator. modul med en mikroservice til at acceptere transaktioner via Rest;
- handelsforespørgsler. modul med mikroservice til visning af positionen.
Lad os tage Spring Boot som basis og tilslutte Axon-starteren.
Axon fungerer fint uden Spring, men vi bruger dem sammen.
Her er vi nødt til at stoppe op og sige et par ord om Axon.
Det er et klient-server-system. Der er en server - dette er en separat applikation, vi kører den i Docker.
Og der er klienter, der er indbygget i mikrotjenester.
Det billede, der tegner sig, er som følger. Først lanceres Axon-serveren (i Docker), derefter vores microservices.
Når mikrotjenester starter, søger de efter en server og begynder at interagere med den. Interaktion kan betinget opdeles i to typer: teknisk og forretningsmæssig.
Teknisk - dette er udvekslingen af "Jeg er i live"-beskeder (sådanne beskeder kan ses i fejlfindingslogningstilstand).
Forretning er udveksling af beskeder som "ny aftale".
En vigtig funktion er, at mikrotjenesten efter lancering kan spørge Axon-serveren "hvad der skete", og serveren sender de akkumulerede hændelser til mikrotjenesten. På denne måde kan mikrotjenesten genstartes relativt sikkert uden at miste data.
Med denne udvekslingsordning kan vi meget nemt lancere mange instanser af mikrotjenester,
og på forskellige værter.
Ja, én instans af Axon-serveren er ikke pålidelig, men for nu er den det.
Vi arbejder inden for Event Sourcing og CQRS-paradigmerne. Det betyder, at vi skal have "kommandoer", "begivenheder" og "valg".
Vi vil have én kommando: "opret en handel", én begivenhed "handel oprettet" og tre valgmuligheder: "vis alle handler", "vis position", "vis position efter instrument".
Arbejdsplanen er som følger:
- Microservice tradeCreator accepterer en handel via REST.
- tradeCreator-mikrotjenesten opretter en "opret en handel"-kommando og sender den til Axon-serveren.
- Axon-serveren modtager kommandoen og videresender den til den interesserede modtager, i vores tilfælde er dette tradeCreator-mikrotjenesten.
- tradeCreator-mikrotjenesten modtager en kommando, genererer en "deal created"-hændelse og sender den til Axon-serveren.
- Axon-serveren modtager begivenheden og videresender den til interesserede abonnenter.
- Lige nu har vi kun én interesseret modtager - mikrotjenesten tradeQueries.
- tradeQueries-mikrotjenesten modtager hændelsen og opdaterer interne data.
(Det er vigtigt, at tradeQueries Microservice muligvis ikke er tilgængelig i det øjeblik, hvor hændelsen genereres, men så snart den starter, vil den straks modtage hændelsen).
Ja, axonserveren er i kommunikationscentret, alle beskeder går igennem den.
Lad os gå videre til kodning.
For ikke at overfylde opslaget med kode, vil jeg kun give fragmenter nedenfor. Linket til det fulde eksempel vil være nedenfor.
Lad os starte med det fælles modul.
De fælles dele i den er hændelsen (klassen CreatedTradeEvent). Vær opmærksom på navnet, det er i bund og grund navnet på det hold, der skabte denne begivenhed, men i datid. I fortiden, fordi Først vises en kommando, der forårsager oprettelsen af hændelsen.
Andre almindelige strukturer omfatter klasser til at beskrive en position (klasse Position), en handel (klasse Trade) og en handelsside (enum Side), dvs. køb eller salg.
Lad os gå videre til tradeCreator-modulet.
Dette modul har en Rest-grænseflade (klasse TradeController) til at acceptere handler.
Fra den modtagne transaktion genereres en "opret transaktion"-kommando, som sendes til axon-serveren.
@PostMapping("/trade")
public ResponseEntity<String> create(@RequestBody Trade trade) {
var createTradeCommand = CreateTradeCommand.builder()
.tradeId(trade.getTradeId())
...
.build();
var result = commandGateway.sendAndWait(createTradeCommand, 3, TimeUnit.SECONDS);
return ResponseEntity.ok(result.get().toString());
}
TradeAggregate-klassen bruges til at behandle kommandoen.
For at Axon skal finde den, indsætter vi @Aggregate annotationen.
Metoden til at behandle en kommando ser sådan ud (forkortet):
@CommandHandler
public TradeAggregate(CreateTradeCommand command) {
log.info("command: {}", command);
var event = CreatedTradeEvent.builder()
.tradeId(command.tradeId())
....
.build();
AggregateLifecycle.apply(event);
}
En hændelse genereres fra kommandoen og sendes til serveren.
Kommandoen er placeret i CreateTradeCommand-klassen.
Lad os nu se på det sidste modul, tradeQueries.
Valgene er beskrevet i forespørgselspakken.
Dette modul har også en Rest-grænseflade.
offentlig klasse Handelscontroller.
Lad os som et eksempel se på behandlingen af anmodningen: "vis alle transaktioner".
@GetMapping("/trade/all")
public List<Trade> findAllTrades() {
return queryGateway.query(new FindAllTradesQuery(),
ResponseTypes.multipleInstancesOf(Trade.class)).join();
}
En hentningsanmodning oprettes og sendes til serveren.
TradesEventHandler-klassen bruges til at behandle udvælgelsesanmodningen.
Den indeholder en metode markeret med annotation
@QueryHandler
public List<Position> handleFindCurrentPositionQuery(FindCurrentPositionQuery query)
Det er ham, der er ansvarlig for at udvælge data fra hukommelsen.
Spørgsmålet opstår, hvordan information opdateres i denne lagring.
Lad os starte med, at dette blot er et sæt ConcurrentHashMaps, skræddersyet til specifikke prøver.
Følgende metode bruges til at opdatere dem:
@EventHandler
public void on(CreatedTradeEvent event) {
log.info("event:{}", event);
var trade = Trade.builder()
...
.build();
trades.put(event.tradeId(), trade);
position.merge(event.shortName(), event.size(),
(oldValue, value) -> event.side() == Side.BUY ? oldValue + value : oldValue - value);
}Den modtager hændelsen "aftale oprettet" og opdaterer kortene.
Dette er hovedpunkterne i udviklingen af mikroservices.
Hvad kan man sige om ulemperne ved Axon?
For det første er dette en komplikation af infrastrukturen; Der er opstået et fejlpunkt – Axon-serveren, al kommunikation går igennem den.
For det andet er ulempen ved sådanne distribuerede systemer ret tydelig – midlertidig datainkonsistens. I vores tilfælde kan der gå uacceptabelt lang tid mellem modtagelse af en ny aftale og opdatering af dataene for prøverne.
Hvad er der tilbage bag kulisserne?
Der siges slet ingenting om Event Sourcing og CQRS, hvad det er, og hvad det er nødvendigt til.
Uden at afklare disse begreber, er nogle punkter muligvis ikke klare.
Måske kræver nogle kodestykker også afklaring.
Vi vil tale om dette på 21 september.
.
Kilde: www.habr.com
