Mikroslužby s komunikací přes Axon

V tomto jednoduchém tutoriálu vytvoříme několik mikroslužeb na Spring Boot a zorganizujeme jejich interakci prostřednictvím frameworku Axon.

Mikroslužby s komunikací přes Axon


Předpokládejme, že máme takový úkol.

Existuje zdroj obchodů na akciovém trhu. Tento zdroj nám předává obchody prostřednictvím REST rozhraní.

Musíme tyto obchody získat, uložit do databáze a vytvořit pohodlné in-memory úložiště.

Toto úložiště by mělo vykonávat následující funkce:

  • vracet seznam obchodů;
  • vracet úplnou pozici, tj. tabulku "nástroj" — "aktuální počet cenných papírů";
  • vracet pozici podle daného nástroje.

Jak přistoupíme k řešení tohoto úkolu?

Podle zásad mikroslužeb musíme úkol rozdělit na jednotlivé mikroslužby:

  • získání obchodu přes REST;
  • uložení obchodu do databáze;
  • in-memory úložiště pro prezentaci dat o pozici.

Pojďme v rámci tohoto tutoriálu vytvořit první a třetí službu, druhou necháme na druhou část (napište do komentářů, pokud je to zajímavé).

Takže máme dvě mikroslužby.

První získává data zvenčí.

Druhá tato data zpracovává a odpovídá na příchozí požadavky.

Samozřejmě chceme dosáhnout horizontálního škálování, bezproblémových aktualizací a dalších výhod mikroslužeb.

Jaký, velmi komplikovaný, úkol před námi stojí?

Ve skutečnosti je jich mnoho, ale teď se pojďme pobavit o tom, jak budou mezi těmito mikroslužbami proudit data. Mezi nimi lze také vytvořit REST, můžete použít nějakou frontu, můžete s mnoha věcmi přijít se svými plusy a mínusy.

Podívejme se na jeden z možných přístupů – asynchronní interakci prostřednictvím frameworku Axon.

Jaké výhody toto řešení přináší?

Za prvé, asynchronní interakce zvyšuje flexibilitu (ano, zde je také nevýhoda, ale nyní jsme právě jen o výhodách).

Za druhé, dostáváme přímo z krabice Event Sourcing a CQRS.
Za třetí, Axon poskytuje hotovou infrastrukturu, a my se musíme soustředit pouze na vývoj obchodní logiky.

Začněme.

Projekt bude na Gradlu. Bude mít tři moduly:

  • common. modul s obecnými datovými strukturami (nemáme rádi kopírování);
  • tradeCreator. modul s mikroslužbou pro přijímání obchodů přes REST;
  • tradeQueries. modul s mikroslužbou pro zobrazení pozice.

Vezmeme Spring Boot jako základ a připojíme Axon starter.

Axon funguje skvěle i bez Springu, ale budeme je používat spolu.

Tady bychom se měli na chvíli zastavit a říct pár slov o Axonu.

Jedná se o klient-server systém. Je tu server – to je samostatná aplikace, kterou spustíme v Dockeru.

A jsou tu klienti, kteří se integrují do mikroservisů.
Vytváří se takový obrázek. Nejprve se spustí Axon server (v Dockeru), a poté naše mikroservisy.

Při spuštění mikroservisy hledají server a začínají s ním komunikovat. Komunikaci můžeme podmíněně rozdělit na dva typy: technickou a obchodní.

Technická – to je výměna zpráv typu 'jsem naživu' (takové zprávy lze vidět v režimu debugování).

Obchodní – to je výměna zpráv typu 'nový obchod'.

Důležitá vlastnost: po spuštění se mikroservis může zeptat Axon serveru 'co se stalo' a server předává mikroservisu nahromaděné události. Takto lze mikroservis relativně bezpečně restartovat bez ztráty dat.
Při takovém schématu výměny můžeme velmi jednoduše spouštět mnoho instancí mikroservisů,
a to i na různých hostitelích.

Ano, jedna instance Axon serveru – to není spolehlivé, ale zatím je to tak.

Pracujeme v paradigma Event Sourcing a CQRS. To znamená, že musíme mít 'příkazy', 'události' a 'dotazy'.

Budeme mít jeden příkaz: 'vytvořit obchod', jednu událost 'obchod vytvořen' a tři dotazy: 'zobrazit všechny obchody', 'zobrazit pozici', 'zobrazit pozici podle nástroje'.

Schéma práce vypadá takto:

  1. Mikroservis tradeCreator přijímá obchod přes Rest.
  2. Mikroservis tradeCreator vytváří příkaz 'vytvořit obchod' a posílá jej do Axon serveru.
  3. Axon server přijímá příkaz a přeposílá ho zúčastněnému příjemci, v našem případě mikroservisu tradeCreator.
  4. Mikroservis tradeCreator obdrží příkaz, vytvoří událost 'obchod vytvořen' a odešle ji Axon serveru.
  5. Axon server přijímá událost a přeposílá ji zainteresovaným odběratelům.
  6. V současnosti máme jen jednoho zainteresovaného příjemce – mikroservis tradeQueries.
  7. Mikroservis tradeQueries obdrží událost a aktualizuje interní data.

(Důležité je, že v okamžiku vytvoření události mikroservis tradeQueries nemusí být dostupný, ale jakmile se spustí, okamžitě obdrží událost).

Ano, Axon server stojí v centru komunikací, všechny zprávy procházejí přes něj.

Přejděme k programování.

Abychom nezahltili příspěvek kódem, níže uvedu pouze fragmenty, odkaz na celý příklad bude níže.

Začneme s obecným modulem common.

V něm jsou společné části – událost (class CreatedTradeEvent). Všimněte si pojmenování, v podstatě to je název příkazu, který tuto událost vyvolal, ale v minulém čase. V minulém čase, protože nejprve se objeví příkaz, který vede k vytvoření události.

Mezi další obecné struktury patří třídy pro popis pozice (class Position), obchodu (class Trade) a strany obchodu (enum Side), tj. koupě nebo prodej.

Přejdeme k modulu tradeCreator.

Tento modul má REST rozhraní (class TradeController) pro přijímání obchodů.
Ze získaného obchodu se vytváří příkaz „vytvořit obchod“ a je odeslán na Axon server.

    @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());
    }

Pro zpracování příkazu se používá třída class TradeAggregate.
Aby ho Axon našel, přidáme anotaci @Aggregate.
Metoda pro zpracování příkazu vypadá takto (s výsečí):

    @CommandHandler
    public TradeAggregate(CreateTradeCommand command) {
        log.info("command: {}", command);
        var event = CreatedTradeEvent.builder()
                .tradeId(command.tradeId())
		....
                .build();
        AggregateLifecycle.apply(event);
    }

Z příkazu se vytváří událost a odesílá se na server.
Příkaz se nachází ve třídě CreateTradeCommand.

Teď se podíváme na poslední modul tradeQueries.

Dotazy jsou popsány v balíčku queries.
V tomto modulu také existuje REST rozhraní
public class TradeController.

Pro příklad se podíváme na zpracování dotazu: „zobrazit všechny obchody“.

    @GetMapping("/trade/all")
    public List findAllTrades() {
        return queryGateway.query(new FindAllTradesQuery(),
                ResponseTypes.multipleInstancesOf(Trade.class)).join();
    }

Vytváří se dotaz na výběr a odesílá se na server.

Pro zpracování dotazu na výběr se používá třída TradesEventHandler.
V ní je metoda, označená anotací

   @QueryHandler
    public List handleFindCurrentPositionQuery(FindCurrentPositionQuery query)

Ta je zodpovědná za výběr dat z in-memory úložiště.

Vybavuje se otázka, jak se v tomto úložišti aktualizují informace.

Začneme tím, že to je prostě sada ConcurrentHashMap, přizpůsobených pro konkrétní výběry.
Pro jejich aktualizaci se používá metoda:

    @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);
    }

Zpracovává událost „obchod vytvořen“ a aktualizuje Mapy.

To jsou hlavní body vývoje mikroslužeb.

Co lze říci o nevýhodách Axonu?

Za prvé, komplikuje se infrastruktura, vzniká bod selhání – Axon server, veškerá komunikace probíhá přes něj.

Za druhé, výrazně se projevuje nevýhoda podobných distribuovaných systémů – dočasná nekonzistentnost dat. V našem případě může mezi získáním nové smlouvy a aktualizací dat pro výběry uplynout nepřijatelně dlouhá doba.

Co zůstalo za oponou?

O Event Sourcing a CQRS nebylo vůbec řečeno, co to je a k čemu je to potřeba.
Bez vysvětlení těchto pojmů mohlo několik bodů zůstat nejasných.

Možná některé fragmenty kódu také vyžadují vysvětlení.

O tom si promluvíme na otevřeném webináři 21. září.

Úplný příklad.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster