Selles lihtsas juhendis loome paar mikroteenust Spring Booti abil ja organiseerime nende vahelise suhtluse Axon raamistikuga.

Oletame, et meil on selline ĂŒlesanne.
On olemas tehingute allikas börsil. See allikas edastab meile tehingud REST liidese kaudu.
Me peame need tehingud kĂ€tte saama, andmebaasi salvestama ja looma mugava in-memory salvestussĂŒsteemi.
See salvestussĂŒsteem peab tĂ€itma jĂ€rgmisi funktsioone:
- tagastama tehingute loendi;
- tagastama tĂ€ieliku positsiooni, st tabeli "vahend" â "praegune aktsiate arv";
- tagastama positsiooni antud vahendi kohta.
Kuidas me sellele ĂŒlesandele lĂ€heneme?
Mikroteenuste moodi kohaselt peame ĂŒlesande jagama komponentideks mikroteenusteks:
- saama tehingud RESTi kaudu;
- salvestama tehingud andmebaasi;
- in-memory salvestussĂŒsteem positsioonide andmete esitlemiseks.
KÀesoleva juhendi raames loome esmase ja kolmanda teenuse, teise jÀtame teise osa jaoks (kommentaaridesse kirjutage, kui see huvitab).
Nii et meil on kaks mikroteenust.
Esimene saadab andmeid vÀljast.
Teine töötleb neid andmeid ja vastab sissetulevatele pÀringutele.
Me tahame muidugi saavutada horisontaalset skaleeritavust, katkestusvaba vÀrskendamist ja muid mikroteenuste eeliseid.
Milline, ĂŒsna keeruline, ĂŒlesanne meie ees seisab?
Tegelikult on neid palju, aga rÀÀgime nĂŒĂŒd sellest, kuidas andmed nende mikroteenuste vahel liiguvad. Nende vahel vĂ”ib ka teha RESTi, kasutada mĂ”nda jĂ€rjekorda, vĂ€lja mĂ”elda palju muid asju oma plusside ja miinustega.
Vaadakem ĂŒhte vĂ”imalikku lĂ€henemist â asĂŒnkroonset suhtlemist lĂ€bi Axon raamistik.
Millised on sellise lahenduse plussid?
Esiteks, asĂŒnkroonne suhtlemine suurendab paindlikkust (jah, siin on ka miinus, kuid rÀÀgime praegu ainult plussidest).
Teiseks, saame otse vĂ€lja arvatud SĂŒndmuste allikaks ja CQRS.
Kolmandaks, Axon annab valmis infrastruktuuri, nii et meie peame keskenduma ainult Àriloogika arendamisele.
Hakkame pihta.
Projekt pÔhineb gradle'il. See sisaldab kolm moodulit:
- common. moodul ĂŒldiste andmestruktuuridega (me ei armasta kopeerimist);
- tradeCreator. moodul mikroteenuse jaoks, et vastu vÔtta tehinguid RESTi kaudu;
- tradeQueries. moodul mikroteenuse jaoks positsiooni kuvamiseks.
VĂ”tame aluseks Spring Booti ja ĂŒhendame Axoni aluse.
Axon töötab suurepÀraselt ka ilma Springita, kuid me kasutame neid koos.
Siin tasub peatuda ja paar sÔna Axoni kohta rÀÀkida.
See on klient-server sĂŒsteem. On server â see on eraldi rakendus, mida kĂ€ivitame Dockeris.
Ja on kliendid, mis integreeruvad mikroteenustesse.
Nii et pilt on jÀrgmine. Esiteks kÀivitatakse Axon-server (Dockeris), seejÀrel meie mikroteenused.
KÀivitusel otsivad mikroteenused serverit ja hakkavad temaga suhtlema. Suhtlemine on tinglikult jagatud kaheks: tehniliseks ja Àriliseks.
Tehniline â see on sĂ”numite vahetus "ma olen elus" (selliseid sĂ”numeid vĂ”ib nĂ€ha debug-reĆŸiimis).
Ăriline â see on sĂ”numite vahetus nagu "uus tehing".
Oluline omadus on see, et pĂ€rast kĂ€ivitamist vĂ”ib mikroteenus kĂŒsida Axon-serverilt "mis juhtus" ja server edastab mikroteenusele kogunenud sĂŒndmused. Nii saab mikroteenus suhteliselt ohutult taaskĂ€ivituda ilma andmete kaota.
Sellise suhtlemise skeemi puhul saame vÀga lihtsalt kÀivitada mitu mikroteenuse eksemplari,
isegi erinevates hostides.
Jah, ĂŒks Axon-serveri eksemplar ei ole usaldusvÀÀrne, aga praegu on see nii.
Me töötame Event Sourcing ja CQRS paradigmades. See tĂ€hendab, et meil peavad olema 'kĂ€sklused', 'sĂŒndmused' ja 'valikud'.
Meil on ĂŒks kĂ€sklus: 'loo tehing', ĂŒks sĂŒndmus 'tehing loodud' ja kolm valikut: 'nĂ€ita kĂ”iki tehinguid', 'nĂ€ita positsiooni', 'nĂ€ita positsiooni tööriista jĂ€rgi'.
Töö skeem on jÀrgmine:
- Mikroteenus tradeCreator vÔtab tehingu vastu Rest kaudu.
- Mikroteenus tradeCreator loob kÀskluse 'loo tehing' ja saadab selle Axon-serverile.
- Axon-server vÔtab kÀskluse vastu ja edastab selle huvitatud adressaadile, meie puhul mikroteenusele tradeCreator.
- Mikroteenus tradeCreator saab kĂ€skluse, vormib sĂŒndmuse 'tehing loodud' ja saadab selle Axon-serverile.
- Axon-server vĂ”tab sĂŒndmuse vastu ja edastab selle huvitatud tellijatele.
- Praegu on meil ainult ĂŒks huvitatud adressaat â mikroteenus tradeQueries.
- Mikroteenus tradeQueries saab sĂŒndmuse ja uuendab siseandmeid.
(Oluline, et sĂŒndmuse loomise hetkel vĂ”ib mikroteenus tradeQueries olla mitte kĂ€ttesaadav, kuid niipea, kui ta kĂ€ivitub, saab ta kohe sĂŒndmuse).
Jah, axon-server on suhtluse keskmes, kÔik sÔnumid lÀhevad lÀbi selle.
Hakake edasi kodeerimisele.
Kuna postitust ei taha koormata koodiga, toon allpool ainult fragmendid, link tÀispikale nÀitele tuleb samuti allpool.
Alustame ĂŒldise mooduliga common.
Selles on ĂŒldised osad - see on sĂŒndmus (class CreatedTradeEvent). Pange tĂ€hele nimetust, see on pĂ”himĂ”tteliselt meeskonna nimi, mis selle sĂŒndmuse tekitas, kuid minevikuvormis. Minevikuvormis, kuna kĂ”igepealt tekib meeskond, mis viib sĂŒndmuse loomiseni.
Teiste ĂŒldiste struktuuride hulka kuuluvad klassid positsiooni kirjeldamiseks (class Position), tehingu (class Trade) ja tehingu pool (enum Side), st ost vĂ”i mĂŒĂŒk.
Liigume tradeCreator moodulisse.
Selles moodulis on Rest-liidese (class TradeController) jaoks tehingute vastuvÔtmise vÔimalus.
Saadud tehingust moodustatakse kÀsk «loo tehing» ja saadetakse axon-serverisse.
@PostMapping("/trade")
public ResponseEntity 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());
}
KÀsku töödeldakse klassi class TradeAggregate abil.
Kuna Axon peab selle leidma, asetame annotatsiooni @Aggregate.
KĂ€skude töötlemise meetod nĂ€eb vĂ€lja selline (lĂŒhendatult):
@CommandHandler
public TradeAggregate(CreateTradeCommand command) {
log.info("command: {}", command);
var event = CreatedTradeEvent.builder()
.tradeId(command.tradeId())
....
.build();
AggregateLifecycle.apply(event);
}
KĂ€skude pĂ”hjal moodustatakse sĂŒndmus ja saadetakse serverisse.
KĂ€sk asub klassis CreateTradeCommand.
NĂŒĂŒd vaatame viimast moodulit tradeQueries.
KĂŒsimused on kirjeldatud paketis queries.
Selles moodulis on samuti Rest-liides.
public class TradeController.
NÀiteks vaatame pÀringute töötlemist: «nÀita kÔiki tehinguid».
@GetMapping("/trade/all")
public List findAllTrades() {
return queryGateway.query(new FindAllTradesQuery(),
ResponseTypes.multipleInstancesOf(Trade.class)).join();
}
Loetakse pÀring valiku tegemiseks ja saadetakse serverisse.
PÀringu töötlemiseks kasutatakse klassi TradesEventHandler.
Selles on meetod, mis on mÀrgitud annotatsiooniga.
@QueryHandler
public List handleFindCurrentPositionQuery(FindCurrentPositionQuery query)
Just tema vastutab andmete valimise eest in-memory andmehoidlast.
KĂŒsimus on, kuidas selles andmehoidlas uut teavet uuendatakse.
Alustame sellest, et see on lihtsalt hulk ConcurrentHashMap'e, mis on suunatud konkreetsetele pÀringutele.
Nende uuendamiseks kasutatakse meetodit:
@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);
}See sĂŒndmus "kaubanduse loomine" ja uuendab kaardid.
Need on mikroteenuste arendamise peamised punktid.
Mida saab öelda Axoni puuduste kohta?
Esiteks, see keerustab infrastruktuuri, tekib rikke punkt â Axon server, kĂ”ik suhtlused kĂ€ivad lĂ€bi selle.
Teiseks, sarnaste hajutatud sĂŒsteemide puudus avaldub selgelt â andmete ajutine konsistentsus. Meie puhul vĂ”ib uue tehingu saamise ja andmete uuendamise vahel lĂ€bida liiga palju aega.
Mis jÀi varju?
Kohapeal ei ole midagi öeldud Event Sourcing ja CQRS kohta, mis need on ja milleks neid vaja on.
Ilma nende mÔistete selgitamiseta vÔivad mÔned punktid jÀÀda arusaamatuks.
VÔib-olla vajavad ka mÔned koodifragmendid selgitamist.
Sellest rÀÀgime 21. septembril.
.
Allikas: habr.com
