![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Die bou van 'n betroubare, hoogs beskikbare, skaalbare verspreide stelsel vereis nakoming van spesifieke tegnieke, beginsels en patrone. Die ontwerp van sulke stelsels behels die aanspreek van 'n magdom uitdagings. Een van die mees algemene en fundamentele kwessies is die dubbelskryfprobleem .
Die "dubbelskryfprobleem" is 'n uitdaging wat in verspreide stelsels ontstaan, hoofsaaklik wanneer daar met veelvuldige databronne of databasisse te make word wat gesinchroniseer moet word. Dit verwys na die moeilikheid om te verseker dat dataveranderinge konsekwent na verskeie datawinkels geskryf word, soos databasisse of kas, sonder om kwessies soos data-inkonsekwenthede, konflikte of prestasie-bottelnekke bekend te stel.
Die mikrodienste-argitektuur en patroondatabasis per diens bring vir jou baie voordele, soos onafhanklike ontplooiing en skaal, geïsoleerde mislukkings en 'n potensiële hupstoot van ontwikkelingsnelheid. Bedrywighede vereis egter veranderinge tussen verskeie mikrodienste, wat jou dwing om te dink aan 'n betroubare oplossing om hierdie probleem aan te pak.
Kom ons kyk na 'n scenario waarin ons domein die aanvaarding van leningsaansoeke behels, dit beoordeel en dan kennisgewingwaarskuwings aan kliënte stuur.
In die gees van die enkelverantwoordelikheidsbeginsel, Conway se wet, en domeingedrewe ontwerpbenadering, is die hele domein na verskeie gebeurtenisstormsessies in drie subdomeine verdeel met gedefinieerde begrensde kontekste met duidelike grense, domeinmodelle en alomteenwoordige taal.
Die eerste het die taak om nuwe leningsaansoeke aan te boord en saam te stel. Die tweede stelsel evalueer hierdie aansoeke en neem besluite op grond van die data wat verskaf word. Hierdie assesseringsproses, insluitend KYC/KYB, antibedrog- en kredietrisikokontroles, kan tydrowend wees, wat die vermoë vereis om duisende aansoeke gelyktydig te hanteer. Gevolglik is hierdie funksionaliteit gedelegeer na 'n toegewyde mikrodiens met sy eie databasis, wat onafhanklike skaal moontlik maak.
Verder word hierdie substelsels deur twee verskillende spanne bestuur, elk met sy eie vrystellingsiklusse, diensvlakooreenkomste (SLA) en skaalbaarheidsvereistes.
Laastens is 'n gespesialiseerde kennisgewingdiens in plek om waarskuwings aan kliënte te stuur.
Hier is 'n verfynde beskrywing van die primêre gebruiksgeval van die stelsel:
Dit is met die eerste oogopslag 'n redelik eenvoudige en primitiewe stelsel, maar kom ons kyk na hoe die Lening-aansoekdiens die opdrag om die leningaansoek in te dien verwerk.
Ons kan twee benaderings vir diensinteraksies oorweeg:
First-Local-Commit-Then-Publish: In hierdie benadering werk die diens sy plaaslike databasis op (commits) en publiseer dan 'n gebeurtenis of boodskap aan ander dienste.
Eerste-Publiseer-Dan-Plaaslik-Commit: Omgekeerd behels hierdie metode die publikasie van 'n gebeurtenis of boodskap voordat die veranderinge aan die plaaslike databasis toegepas word.
Beide metodes het hul nadele en is slegs gedeeltelik faalveilig vir kommunikasie in verspreide stelsels.
Dit is 'n volgordediagram van die toepassing van die eerste benadering.
In hierdie scenario gebruik die Leningsaansoekdiens die Eerste-Plaas-Commit-Dan-Publiseer- benadering, waar dit eers 'n transaksie pleeg en dan probeer om 'n kennisgewing na 'n ander stelsel te stuur. Hierdie proses is egter vatbaar vir mislukking as daar byvoorbeeld netwerkkwessies is, die Assesseringsdiens nie beskikbaar is nie, of die Leningsaansoekdiens 'n Out of Memory (OOM)-fout teëkom en ineenstort. In sulke gevalle sal die boodskap verlore gaan, wat die Assessering verlaat sonder kennisgewing van die nuwe leningsaansoek, tensy bykomende maatreëls geïmplementeer word.
En die tweede een.
In die Eerste-Publiseer-Dan-Plaas-Commit- scenario, staar die Leningsaansoekdiens groter risiko's in die gesig. Dit kan die Assesseringsdiens inlig oor 'n nuwe toepassing, maar versuim om hierdie opdatering plaaslik te stoor as gevolg van probleme soos databasiskwessies, geheuefoute of kodefoute. Hierdie benadering kan lei tot aansienlike teenstrydighede in data, wat ernstige probleme kan veroorsaak, afhangende van hoe die Leningshersieningsdiens inkomende aansoeke hanteer.
Daarom moet ons 'n oplossing identifiseer wat 'n robuuste meganisme bied om geleenthede aan eksterne verbruikers te publiseer. Maar voordat ons in potensiële oplossings delf, moet ons eers die tipe boodskapleweringswaarborge wat in verspreide stelsels haalbaar is, duidelik maak.
Daar is vier tipes waarborge wat ons kan bereik.
Geen waarborge nie
Daar is geen waarborg dat die boodskap by die bestemming afgelewer sal word nie. Die benadering Eerste-Plaas-Verbind-Dan-Publiseer gaan juis hieroor. Verbruikers kan boodskappe een keer, veelvuldige kere of glad nie ontvang nie.
Hoogstens een keer aflewering
Hoogstens een keer aflewering beteken dat die boodskap hoogstens 1 keer by die bestemming afgelewer sal word. Die benadering Eerste-Plaas-Verbind-Dan-Publiseer kan ook op hierdie manier geïmplementeer word met die herprobeerbeleid van pogings met waarde een.
Ten minste een keer aflewering\Verbruikers sal elke boodskap ontvang en verwerk, maar kan dieselfde boodskap meer as een keer ontvang.
Presies een keer aflewering\Presies een keer aflewering beteken dat die verbruiker die boodskap effektief een keer sal ontvang.
Tegnies is dit moontlik om met Kafka transaksies en spesifieke idempotente implementering van produsent en verbruiker te bereik.
In die meeste gevalle spreek 'ten minste een keer' afleweringswaarborge baie kwessies aan deur te verseker dat boodskappe ten minste een keer afgelewer word, maar verbruikers moet idempotent wees. Gegewe die onvermydelike netwerkfoute, moet alle verbruikerslogika egter idempotent wees om die verwerking van duplikaatboodskappe te vermy, ongeag die produsent se waarborge. Daarom is hierdie vereiste nie soseer 'n nadeel nie, aangesien dit die werklikheid weerspieël.
Daar is baie oplossings vir hierdie probleem, wat hul voordele en nadele het.
Volgens Wikipedia is die Two-Phase Commit (2PC) 'n verspreide transaksieprotokol wat in rekenaarwetenskap en databasisbestuurstelsels gebruik word om die konsekwentheid en betroubaarheid van verspreide transaksies te verseker. Dit is ontwerp vir situasies waar veelvuldige hulpbronne (bv. databasisse) aan 'n enkele transaksie moet deelneem, en dit verseker dat óf almal die transaksie pleeg óf almal van hulle staak dit, en sodoende datakonsekwentheid behou. Dit klink presies wat ons nodig het, maar Two-Phase Commit het verskeie nadele:
Die duidelikste oplossing vir mikrodienste-argitektuur is om 'n patroon (of selfs soms anti-patroon) toe te pas - 'n gedeelde databasis. Hierdie benadering is baie intuïtief as jy transaksionele konsekwentheid oor verskeie tabelle in verskillende databasisse benodig, gebruik net een gedeelde databasis vir hierdie mikrodienste.
Die nadele van hierdie benadering sluit in die bekendstelling van 'n enkele punt van mislukking, die inhibering van onafhanklike databasisskaal, en die beperking van die vermoë om verskillende databasisoplossings te gebruik wat die beste geskik is vir spesifieke vereistes en gebruiksgevalle. Boonop sal wysigings aan die mikrodienste-kodebasisse nodig wees om so 'n vorm van verspreide transaksie te ondersteun.
Die ' transaksionele uitboks ' is 'n ontwerppatroon wat in verspreide stelsels gebruik word om betroubare boodskapverspreiding te verseker, selfs in die lig van onbetroubare boodskapstelsels. Dit behels die stoor van gebeure in 'n aangewese 'OutboxEvents'-tabel binne dieselfde transaksie as die operasie self. Hierdie benadering strook goed met ACID eienskappe van relasionele databasisse. Daarteenoor ondersteun baie No-SQL-databasisse nie ACID-eienskappe ten volle nie, maar kies eerder die beginsels van die CAP-stelling en BASE-filosofie, wat beskikbaarheid en uiteindelike konsekwentheid prioritiseer bo streng konsekwentheid.
'n Transaksionele uitboks bied ten minste een keer waarborg en kan met verskeie benaderings geïmplementeer word:
Transaksie log tailing
Polling uitgewer
Transaksie log tailing benadering impliseer die gebruik van databasis-spesifieke oplossings soos CDC (Change Data Capture). Die belangrikste nadele van daardie benadering is:
Databasis spesifieke oplossings
Verhoogde latensie as gevolg van die besonderhede van CDC-implementerings
Nog 'n metode is die Polling Publisher , wat die uitboksaflaai vergemaklik deur die uitbokstabel te stem. Die primêre nadeel van hierdie benadering is die potensiaal vir verhoogde databasislading, wat tot hoër koste kan lei. Verder ondersteun nie alle No-SQL-databasisse doeltreffende navrae vir spesifieke dokumentsegmente nie. Die onttrekking van hele dokumente kan dus lei tot agteruitgang in prestasie.
Hier is 'n klein volgordediagram wat verduidelik hoe dit werk.
Die primêre uitdaging met die Transactional Outbox-patroon lê in sy afhanklikheid van databasis ACID-eienskappe. Dit kan eenvoudig wees in tipiese OLTP-databasisse, maar bied uitdagings in die NoSQL-ryk. Om dit aan te spreek, is 'n moontlike oplossing om die byvoeglogboek (byvoorbeeld Kafka) te gebruik vanaf die aanvang van versoekverwerking.
In plaas daarvan om die 'dien leningaansoek'-opdrag direk te verwerk, stuur ons dit onmiddellik na 'n interne Kafka-onderwerp en stuur dan 'n 'aanvaarde' resultaat aan die kliënt terug. Aangesien dit egter hoogs waarskynlik is dat die opdrag nog verwerk moet word, kan ons nie dadelik die kliënt van die resultaat in kennis stel nie. Om hierdie uiteindelike konsekwentheid te bestuur, kan ons tegnieke gebruik soos lang peiling, kliënt-geïnisieerde peiling, optimistiese UI-opdaterings, of die gebruik van WebSockets of Server-Sent Events vir kennisgewings. Dit is egter heeltemal 'n afsonderlike onderwerp, so kom ons keer terug na ons aanvanklike onderwerp.
Ons het die boodskap oor 'n interne Kafka-onderwerp gestuur. Die leningaansoekdiens gebruik dan hierdie boodskap - dieselfde opdrag wat dit van die kliënt ontvang het - en begin verwerk. Eerstens voer dit 'n paar besigheidslogika uit; eers nadat hierdie logika suksesvol uitgevoer is en die resultate volgehou word, publiseer dit nuwe boodskappe oor 'n openbare Kafka-onderwerp.
Kom ons kyk na 'n bietjie pseudo-kode.
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(); }
Wat as die verwerking van die besigheidslogika misluk? Geen bekommernisse nie, aangesien die verrekening nog nie toegepas is nie, sal die boodskap herprobeer word.
Wat as die stuur van nuwe gebeure na Kafka misluk? Geen bekommernisse nie, aangesien die besigheidslogika idempotent is, sal dit nie 'n duplikaatleningsaansoek skep nie. In plaas daarvan sal dit probeer om boodskappe weer na die openbare Kafka-onderwerp te stuur.
Wat as boodskappe aan Kafka gestuur word, maar die verreken-toewysing misluk? Geen bekommernisse nie, aangesien die besigheidslogika idempotent is, sal dit nie 'n duplikaatleningsaansoek skep nie. In plaas daarvan sal dit weer boodskappe na die publieke Kafka-onderwerp stuur en hoop dat die verrekeningstoewysing hierdie keer slaag.
Die belangrikste nadele van hierdie benadering sluit in die bykomende kompleksiteit wat verband hou met 'n nuwe programmeringstyl, uiteindelike konsekwentheid (aangesien die kliënt nie dadelik die resultaat sal weet nie), en die vereiste dat alle besigheidslogika idempotent moet wees.
Wat is gebeurtenisverkryging, en hoe kan dit hier toegepas word? Gebeurtenisverkryging is 'n sagteware-argitektoniese patroon wat gebruik word om die toestand van 'n stelsel te modelleer deur alle veranderinge aan sy data vas te lê as 'n reeks onveranderlike gebeurtenisse. Hierdie gebeure verteenwoordig feite of staatsoorgange en dien as die enkele bron van waarheid vir die sisteem se huidige toestand. Dus, tegnies, deur die implementering van 'n gebeurtenis-verkrygingstelsel, het ons reeds alle gebeurtenisse in EventStore, en hierdie EventStore kan deur verbruikers gebruik word as 'n enkele bron van waarheid oor wat gebeur het. Daar is geen behoefte aan 'n spesifieke databasisoplossing om alle veranderinge of bekommernisse oor bestellings op te spoor nie, die enigste probleem is om aan die leeskant te sit, aangesien dit nodig is om alle gebeurtenisse te herspeel om die werklike toestand van die entiteit te kan kry.
In hierdie artikel het ons verskeie benaderings hersien vir die bou van betroubare boodskappe in verspreide stelsels. Daar is verskeie aanbevelings wat ons kan oorweeg wanneer ons stelsels met hierdie eienskappe bou
Volgende keer sal ons kyk na 'n meer praktiese voorbeeld van die implementering van 'n Transaksionele Uitboks. Sien
jy!