![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Luotettavan, erittäin saatavilla olevan, skaalautuvan hajautetun järjestelmän rakentaminen edellyttää tiettyjen tekniikoiden, periaatteiden ja mallien noudattamista. Tällaisten järjestelmien suunnitteluun liittyy lukemattomien haasteiden ratkaiseminen. Yksi yleisimmistä ja perustavimmista ongelmista on kaksoiskirjoitusongelma .
"Kaksoiskirjoitusongelma" on haaste, joka ilmenee hajautetuissa järjestelmissä, pääasiassa silloin, kun käsitellään useita tietolähteitä tai tietokantoja, jotka on pidettävä synkronoituna. Se viittaa vaikeuteen varmistaa, että tietojen muutokset kirjoitetaan johdonmukaisesti eri tietovarastoihin, kuten tietokantoihin tai välimuistiin, aiheuttamatta ongelmia, kuten tietojen epäjohdonmukaisuuksia, ristiriitoja tai suorituskyvyn pullonkauloja.
Mikropalveluarkkitehtuuri ja palvelukohtainen mallitietokanta tuovat sinulle monia etuja, kuten itsenäisen käyttöönoton ja skaalauksen, yksittäisiä vikoja ja mahdollisen kehitysnopeuden lisäämisen. Toiminta vaatii kuitenkin muutoksia useiden mikropalvelujen välillä, mikä pakottaa sinut miettimään luotettavaa ratkaisua ongelman ratkaisemiseksi.
Tarkastellaan skenaariota, jossa toimialueemme sisältää lainahakemusten hyväksymisen, arvioinnin ja ilmoitushälyttien lähettämisen asiakkaille.
Yhden vastuun periaatteen, Conwayn lain ja toimialuelähtöisen suunnittelun hengessä useiden tapahtumariippuvaisten istuntojen jälkeen koko toimialue jaettiin kolmeen aliverkkoalueeseen, joissa oli määritellyt rajatut kontekstit, joilla oli selkeät rajat, toimialuemallit ja kaikkialla esiintyvä kieli.
Ensimmäisen tehtävänä on ottaa käyttöön ja laatia uusia lainahakemuksia. Toinen järjestelmä arvioi nämä hakemukset ja tekee päätökset annettujen tietojen perusteella. Tämä arviointiprosessi, mukaan lukien KYC/KYB, petostentorjunta ja luottoriskitarkistukset, voi olla aikaa vievä, mikä edellyttää kykyä käsitellä tuhansia hakemuksia samanaikaisesti. Tästä syystä tämä toiminto on delegoitu erilliselle mikropalvelulle, jolla on oma tietokanta, mikä mahdollistaa itsenäisen skaalauksen.
Lisäksi näitä alijärjestelmiä hallinnoi kaksi eri tiimiä, joilla kullakin on omat julkaisujaksonsa, palvelutasosopimukset (SLA) ja skaalautuvuusvaatimukset.
Lisäksi käytössä on erikoistunut ilmoituspalvelu, joka lähettää hälytyksiä asiakkaille.
Tässä on tarkennettu kuvaus järjestelmän ensisijaisesta käyttötapauksesta:
Se on ensisilmäyksellä melko yksinkertainen ja primitiivinen järjestelmä, mutta sukeltakaamme kuinka Lainahakemuspalvelu käsittelee Lähetä lainahakemus -komentoa.
Voimme harkita kahta lähestymistapaa palveluvuorovaikutuksiin:
First-Local-Commit-Then-Publish: Tässä lähestymistavassa palvelu päivittää paikallisen tietokantansa (sitoutuu) ja julkaisee sitten tapahtuman tai viestin muille palveluille.
Ensin-julkaise-ja sitten-paikallinen-sitoumus: Päinvastoin, tämä menetelmä sisältää tapahtuman tai viestin julkaisemisen ennen muutosten tekemistä paikalliseen tietokantaan.
Molemmilla menetelmillä on haittapuolensa, ja ne ovat vain osittain vikaturvallisia hajautettujen järjestelmien tietoliikenteeseen.
Tämä on sekvenssikaavio ensimmäisen lähestymistavan soveltamisesta.
Tässä skenaariossa lainahakemuspalvelu käyttää First-Local-Commit-Then-Publish -lähestymistapaa, jossa se ensin sitoo tapahtuman ja yrittää sitten lähettää ilmoituksen toiseen järjestelmään. Tämä prosessi voi kuitenkin epäonnistua, jos esimerkiksi verkko-ongelmia ilmenee, arviointipalvelu ei ole käytettävissä tai Lainahakemuspalvelu havaitsee Muisti täynnä (OOM) -virheen ja kaatuu. Tällaisissa tapauksissa viesti katoaisi, jolloin Arviointi jätettäisiin ilman ilmoitusta uudesta lainahakemuksesta, ellei lisätoimenpiteitä toteuteta.
Ja toinen.
Ensin julkaise ja sitten paikallinen sitoumus -skenaariossa lainahakemuspalveluun liittyy merkittävämpiä riskejä. Se saattaa ilmoittaa arviointipalvelulle uudesta sovelluksesta, mutta ei voi tallentaa tätä päivitystä paikallisesti ongelmien, kuten tietokantaongelmien, muistivirheiden tai koodivirheiden vuoksi. Tämä lähestymistapa voi johtaa merkittäviin epäjohdonmukaisuuksiin tiedoissa, mikä voi aiheuttaa vakavia ongelmia riippuen siitä, kuinka Lainatarkastuspalvelu käsittelee saapuvia hakemuksia.
Siksi meidän on löydettävä ratkaisu, joka tarjoaa vankan mekanismin tapahtumien julkaisemiseen ulkopuolisille kuluttajille. Mutta ennen kuin syvennymme mahdollisiin ratkaisuihin, meidän on ensin selvitettävä hajautetuissa järjestelmissä saavutettavissa olevat viestin toimitustakuutyypit.
Voimme saavuttaa neljän tyyppisiä takuita.
Ei takuita
Ei ole takeita siitä, että viesti toimitetaan perille. Lähestymistapa First-Local-Commit-Then-Publish koskee juuri tätä. Kuluttajat voivat saada viestejä kerran, useita kertoja tai ei koskaan.
Korkeintaan kerran toimitus
Korkeintaan kerran toimitus tarkoittaa, että viesti toimitetaan määränpäähän enintään 1 kerran. Lähestymistapa First-Local-Commit-Then-Publish voidaan toteuttaa tällä tavalla myös uudelleenyrityskäytännöllä arvolla yksi.
Ainakin kerran toimitus\Kuluttajat vastaanottavat ja käsittelevät jokaisen viestin, mutta voivat saada saman viestin useammin kuin kerran.
Täsmälleen kerran toimitus\Täsmälleen kerran toimitus tarkoittaa, että kuluttaja vastaanottaa viestin tehokkaasti kerran.
Teknisesti se on mahdollista saavuttaa Kafka-transaktioilla ja erityisellä tuottajan ja kuluttajan idempotentilla toteutuksella.
Useimmissa tapauksissa "vähintään kerran" toimitustakuu ratkaisee monia ongelmia varmistamalla, että viestit toimitetaan vähintään kerran, mutta kuluttajien on oltava kyvyttömiä. Kuitenkin, kun otetaan huomioon väistämättömät verkkohäiriöt, kaiken kuluttajalogiikan on oltava idempotenttia, jotta vältetään päällekkäisten viestien käsittely tuottajan takuista riippumatta. Siksi tämä vaatimus ei ole niinkään haitta kuin se heijastaa todellisuutta.
Tähän ongelmaan on monia ratkaisuja, joilla on hyvät ja huonot puolensa.
Wikipedian mukaan Two-Phase Commit (2PC) on hajautettu tapahtumaprotokolla, jota käytetään tietojenkäsittelytieteessä ja tietokantojen hallintajärjestelmissä hajautettujen tapahtumien johdonmukaisuuden ja luotettavuuden varmistamiseksi. Se on suunniteltu tilanteisiin, joissa useiden resurssien (esim. tietokantojen) on osallistuttava yhteen tapahtumaan, ja se varmistaa, että ne kaikki sitoutuvat tapahtumaan tai kaikki keskeyttävät sen, mikä säilyttää tietojen johdonmukaisuuden. Se kuulostaa täsmälleen siltä, mitä tarvitsemme, mutta kaksivaiheisella vahvistuksella on useita haittoja:
Ilmeisin ratkaisu mikropalveluarkkitehtuuriin on käyttää mallia (tai joskus jopa anti-mallia) - jaettua tietokantaa. Tämä lähestymistapa on erittäin intuitiivinen, jos tarvitset tapahtumien johdonmukaisuutta useiden eri tietokantojen taulukoiden välillä. Käytä vain yhtä jaettua tietokantaa näille mikropalveluille.
Tämän lähestymistavan haittoja ovat yhden vikakohdan käyttöönotto, itsenäisen tietokannan skaalauksen estäminen ja kyky käyttää erilaisia tietokantaratkaisuja, jotka parhaiten sopivat tiettyihin vaatimuksiin ja käyttötapauksiin. Lisäksi mikropalveluiden koodikantoihin olisi tehtävä muutoksia tukemaan tällaista hajautetun tapahtuman muotoa.
Tapahtuman lähtevä laatikko on suunnittelumalli, jota käytetään hajautetuissa järjestelmissä viestien luotettavan etenemisen varmistamiseksi, jopa epäluotettavien viestintäjärjestelmien yhteydessä. Se sisältää tapahtumien tallentamisen määritettyyn OutboxEvents-taulukkoon samassa tapahtumassa kuin itse toiminto. Tämä lähestymistapa sopii hyvin relaatiotietokantojen ACID-ominaisuuksiin. Sitä vastoin monet No-SQL-tietokannat eivät täysin tue ACID-ominaisuuksia, vaan valitsevat sen sijaan CAP-lauseen ja BASE-filosofian periaatteet, jotka priorisoivat saatavuuden ja mahdollisen johdonmukaisuuden tiukan johdonmukaisuuden sijaan.
Lähtevät tapahtumat tarjoavat vähintään kerran takuun , ja se voidaan toteuttaa useilla eri tavoilla:
Tapahtumalokin pyrstö
Äänestyksen julkaisija
Tapahtumalokien pyrstömenetelmä edellyttää tietokantakohtaisten ratkaisujen, kuten CDC:n (Change Data Capture) käyttöä. Tämän lähestymistavan tärkeimmät haitat ovat:
Tietokantakohtaiset ratkaisut
Lisääntynyt latenssi CDC-toteutusten erityispiirteiden vuoksi
Toinen tapa on Polling Publisher , joka helpottaa lähtevien viestien purkamista kyselyllä lähtevät taulukosta. Tämän lähestymistavan ensisijainen haittapuoli on mahdollisuus lisätä tietokannan kuormitusta, mikä voi johtaa korkeampiin kustannuksiin. Lisäksi kaikki No-SQL-tietokannat eivät tue tiettyjen asiakirjasegmenttien tehokasta kyselyä. Kokonaisten asiakirjojen purkaminen voi siten johtaa suorituskyvyn heikkenemiseen.
Tässä on pieni sekvenssikaavio, joka selittää kuinka se toimii.
Transactional Outbox -mallin ensisijainen haaste on sen riippuvuus tietokannan ACID-ominaisuuksista. Se saattaa olla yksinkertaista tyypillisissä OLTP-tietokannoista, mutta aiheuttaa haasteita NoSQL-alueella. Tämän ratkaisemiseksi mahdollinen ratkaisu on hyödyntää liitelokia (esimerkiksi Kafka) heti pyynnön käsittelyn aloittamisesta.
Sen sijaan, että käsittelemme suoraan "lähetä lainahakemus" -komentoa, lähetämme sen välittömästi sisäiseen Kafka-aiheeseen ja palautamme sitten asiakkaalle "hyväksytty" tuloksen. Koska on kuitenkin erittäin todennäköistä, että komento on vielä käsiteltävä, emme voi heti ilmoittaa asiakkaalle tuloksesta. Tämän mahdollisen johdonmukaisuuden hallitsemiseksi voimme käyttää tekniikoita, kuten pitkiä kyselyitä, asiakaslähtöistä kyselyä, optimistisia käyttöliittymäpäivityksiä tai WebSockets- tai Server-Sent Events -tapahtumia ilmoituksiin. Tämä on kuitenkin täysin erillinen aihe, joten palataanpa alkuperäiseen aiheeseen.
Lähetimme viestin sisäisestä Kafka-aiheesta. Lainahakemuspalvelu käyttää tämän viestin – saman komennon, jonka se sai asiakkaalta – ja aloittaa käsittelyn. Ensinnäkin se toteuttaa jonkin verran liiketoimintalogiikkaa; vasta kun tämä logiikka on suoritettu onnistuneesti ja tulokset säilyvät, se julkaisee uusia viestejä julkisesta Kafka-aiheesta.
Katsotaanpa hieman pseudokoodia.
public async Task HandleAsync(SubmitLoanApplicationCommand command, ...) { //First, process business logic var loanApplication = await _loanApplicationService.HandleCommandAsync(command, ...); //Then, send new events to public Kafka topic producer.Send(new LoanApplicationSubmittedEvent(loanApplication.Id)); //Then, commit offset consumer.Commit(); }
Entä jos liiketoimintalogiikan käsittely epäonnistuu? Ei hätää, koska siirtoa ei ole vielä tehty, viestiä yritetään uudelleen.
Entä jos uusien tapahtumien lähettäminen Kafkalle epäonnistuu? Ei hätää, koska liiketoimintalogiikka on idempotentti, se ei luo päällekkäistä lainahakemusta. Sen sijaan se yrittää lähettää viestejä uudelleen julkiseen Kafka-aiheeseen.
Entä jos viestejä lähetetään Kafkalle, mutta offset-sitoumus epäonnistuu? Ei hätää, koska liiketoimintalogiikka on idempotentti, se ei luo päällekkäistä lainahakemusta. Sen sijaan se lähettää viestejä uudelleen julkiselle Kafka-aiheelle ja toivoo, että offset-sitoumus onnistuu tällä kertaa.
Tämän lähestymistavan suurimpia haittoja ovat uuteen ohjelmointityyliin liittyvä monimutkaisuus, mahdollinen johdonmukaisuus (koska asiakas ei heti tiedä tulosta) ja vaatimus, että kaikki liiketoimintalogiikka on idempotentti.
Mitä tapahtuman hankinta on ja miten sitä voitaisiin soveltaa täällä? Tapahtuman hankinta on ohjelmistoarkkitehtuurimalli, jota käytetään mallintamaan järjestelmän tilaa tallentamalla kaikki sen datan muutokset muuttumattomien tapahtumien sarjana. Nämä tapahtumat edustavat tosiasioita tai tilasiirtymiä ja toimivat ainoana totuuden lähteenä järjestelmän nykyiselle tilalle. Joten teknisesti toteuttamalla tapahtumalähdejärjestelmän meillä on jo kaikki tapahtumat EventStoressa, ja kuluttajat voivat käyttää tätä EventStorea yhtenä totuuden lähteenä tapahtuneesta. Kaikkien muutosten tai tilaukseen liittyvien huolenaiheiden seuraamiseen ei tarvita erityistä tietokantaratkaisua, ainoa ongelma on istuminen lukupuolella, koska kokonaisuuden todellisen tilan saaminen edellyttää kaikkien tapahtumien toistamista.
Tässä artikkelissa tarkastelimme useita lähestymistapoja luotettavan viestinnän rakentamiseen hajautetuissa järjestelmissä. Saatamme harkita useita suosituksia rakentaessamme järjestelmiä, joilla on nämä ominaisuudet
Seuraavalla kerralla tarkastellaan käytännöllisempää esimerkkiä Lähtevien tapahtumien käyttöönotosta. Katso
sinä!