Lai izveidotu uzticamu, ļoti pieejamu, mērogojamu sadalīto sistēmu, ir jāievēro noteiktas metodes, principi un modeļi. Šādu sistēmu projektēšana ietver neskaitāmu problēmu risināšanu. Viena no visizplatītākajām un pamata problēmām ir dubultā rakstīšanas problēma .
“Divkāršās rakstīšanas problēma” ir problēma, kas rodas sadalītās sistēmās, galvenokārt, strādājot ar vairākiem datu avotiem vai datu bāzēm, kuras ir jāsaglabā sinhronizācijā. Tas attiecas uz grūtībām nodrošināt, ka datu izmaiņas tiek konsekventi ierakstītas dažādos datu krātuvēs, piemēram, datu bāzēs vai kešatmiņā, neradot tādas problēmas kā datu neatbilstības, konflikti vai veiktspējas vājās vietas.
Mikropakalpojumu arhitektūra un modeļu datubāze katram pakalpojumam sniedz daudzas priekšrocības, piemēram, neatkarīgu izvietošanu un mērogošanu, izolētas kļūmes un potenciālu attīstības ātruma palielinājumu. Tomēr operācijām ir nepieciešamas izmaiņas starp vairākiem mikropakalpojumiem, liekot jums domāt par uzticamu risinājumu šīs problēmas risināšanai.
Apskatīsim scenāriju, kurā mūsu domēns ietver aizdevuma pieteikumu pieņemšanu, to izvērtēšanu un pēc tam paziņojumu brīdinājumu nosūtīšanu klientiem.
Atbilstoši vienotās atbildības principam, Konveja likumam un uz domēnu orientētai dizaina pieejai pēc vairākām notikumu vētras sesijām viss domēns tika sadalīts trīs apakšdomēnos ar definētiem ierobežotiem kontekstiem ar skaidrām robežām, domēna modeļiem un visuresošu valodu.
Pirmā uzdevums ir iekļauties un apkopot jaunus aizdevuma pieteikumus. Otrā sistēma izvērtē šos pieteikumus un pieņem lēmumus, pamatojoties uz sniegtajiem datiem. Šis novērtēšanas process, tostarp KYC/KYB, krāpšanas apkarošana un kredītriska pārbaudes, var būt laikietilpīgs, tādēļ ir nepieciešama iespēja vienlaikus apstrādāt tūkstošiem pieteikumu. Līdz ar to šī funkcionalitāte ir deleģēta īpašam mikropakalpojumam ar savu datu bāzi, kas ļauj veikt neatkarīgu mērogošanu.
Turklāt šīs apakšsistēmas pārvalda divas dažādas komandas, katrai no tām ir savi izlaišanas cikli, pakalpojumu līmeņa līgumi (SLA) un mērogojamības prasības.
Visbeidzot , ir izveidots specializēts paziņojumu pakalpojums, lai nosūtītu brīdinājumus klientiem.
Šeit ir precizēts sistēmas primārās lietošanas gadījuma apraksts:
No pirmā acu uzmetiena tā ir diezgan vienkārša un primitīva sistēma, taču iedziļināsimies tajā, kā Aizdevuma pieteikumu dienests apstrādā aizdevuma pieteikuma iesniegšanas komandu.
Mēs varam apsvērt divas pieejas pakalpojumu mijiedarbībai:
First-Local-Commit-Then-Publish: izmantojot šo pieeju, pakalpojums atjaunina savu lokālo datu bāzi (apņemas) un pēc tam publicē notikumu vai ziņojumu citiem pakalpojumiem.
Vispirms publicējiet, pēc tam lokāli apstipriniet: otrādi, šī metode ietver notikuma vai ziņojuma publicēšanu pirms izmaiņu veikšanas vietējā datu bāzē.
Abām metodēm ir savi trūkumi, un tās ir tikai daļēji drošas saziņai sadalītajās sistēmās.
Šī ir pirmās pieejas piemērošanas secības diagramma.
Šajā scenārijā aizdevuma pieteikuma pakalpojums izmanto pieeju First-Local-commit-then-Publish , kur tas vispirms veic darījumu un pēc tam mēģina nosūtīt paziņojumu citai sistēmai. Tomēr šis process var neizdoties, ja, piemēram, rodas tīkla problēmas, Novērtējuma pakalpojums nav pieejams vai aizdevuma pieteikuma pakalpojums konstatē Trūkst atmiņas (OOM) kļūdu un avarē. Šādos gadījumos ziņojums tiktu pazaudēts, atstājot Novērtējumu bez brīdinājuma par jauno aizdevuma pieteikumu, ja vien netiks īstenoti papildu pasākumi.
Un otrais.
Scenārijā vispirms publicējiet, pēc tam vietējās saistības , aizdevuma pieteikuma pakalpojums saskaras ar nozīmīgākiem riskiem. Tas var informēt novērtēšanas dienestu par jaunu lietojumprogrammu, bet nevar saglabāt šo atjauninājumu lokāli tādu problēmu dēļ kā datu bāzes problēmas, atmiņas kļūdas vai koda kļūdas. Šāda pieeja var radīt būtiskas datu neatbilstības, kas var radīt nopietnas problēmas atkarībā no tā, kā Kredīta pārskatīšanas pakalpojums apstrādā ienākošos pieteikumus.
Tāpēc mums ir jāidentificē risinājums, kas piedāvā stabilu mehānismu notikumu publicēšanai ārējiem patērētājiem. Bet, pirms iedziļināties potenciālajos risinājumos, mums vispirms ir jānoskaidro izplatītajās sistēmās sasniedzamo ziņojumu piegādes garantiju veidi.
Mēs varam sasniegt četru veidu garantijas.
Nekādu garantiju
Nav garantijas, ka ziņojums tiks piegādāts galamērķim. Pieeja First-Local-Commit-Then-Publish ir tieši par to. Patērētāji var saņemt ziņojumus vienu reizi, vairākas reizes vai vispār nesaņemt.
Piegāde ne vairāk kā vienreiz
Ne vairāk kā vienreizēja piegāde nozīmē, ka ziņa tiks piegādāta galamērķim ne vairāk kā 1 reizi. Pieeju First-Local-Commit-Then-Publish var īstenot arī šādā veidā, izmantojot mēģinājumu atkārtošanas politiku ar vērtību viens.
Vismaz vienu reizi piegāde\Patērētāji saņems un apstrādās katru ziņojumu, taču vienu un to pašu ziņojumu var saņemt vairāk nekā vienu reizi.
Precīzi vienreiz piegāde\Tieši vienreiz piegāde nozīmē, ka patērētājs ziņojumu saņems vienu reizi.
Tehniski to iespējams panākt ar Kafkas darījumiem un specifisku idempotentu ražotāja un patērētāja ieviešanu.
Vairumā gadījumu “vismaz vienreizējas” piegādes garantijas risina daudzas problēmas, nodrošinot, ka ziņojumi tiek piegādāti vismaz vienu reizi, taču patērētājiem ir jābūt nespējīgiem. Tomēr, ņemot vērā nenovēršamās tīkla atteices, visai patērētāju loģikai ir jābūt idempotai, lai izvairītos no dublētu ziņojumu apstrādes neatkarīgi no ražotāja garantijām. Tāpēc šī prasība ir ne tik daudz trūkums, cik tā atspoguļo realitāti.
Šai problēmai ir daudz risinājumu, kuriem ir savas priekšrocības un trūkumi.
Saskaņā ar Wikipedia teikto, divu fāžu apņemšanās (2PC) ir izplatīts transakciju protokols, ko izmanto datorzinātnēs un datu bāzu pārvaldības sistēmās, lai nodrošinātu izplatīto darījumu konsekvenci un uzticamību. Tas ir paredzēts situācijām, kad vienā transakcijā ir jāpiedalās vairākiem resursiem (piemēram, datu bāzēm), un tas nodrošina, ka vai nu visi no tiem veic darījumu, vai arī visi to pārtrauc, tādējādi saglabājot datu konsekvenci. Tas izklausās tieši tas, kas mums nepieciešams, taču divu fāzu ieviešanai ir vairāki trūkumi:
Acīmredzamākais risinājums mikropakalpojumu arhitektūrai ir izmantot modeli (vai pat dažreiz anti-paternu) — koplietotu datu bāzi. Šī pieeja ir ļoti intuitīva, ja jums ir nepieciešama darījumu konsekvence vairākās tabulās dažādās datu bāzēs, vienkārši izmantojiet vienu koplietotu datu bāzi šiem mikropakalpojumiem.
Šīs pieejas trūkumi ietver viena atteices punkta ieviešanu, neatkarīgas datu bāzes mērogošanas kavēšanu un iespēju ierobežošanu izmantot dažādus datu bāzes risinājumus, kas ir vislabāk piemēroti konkrētām prasībām un lietošanas gadījumiem. Turklāt, lai atbalstītu šādu izplatītu darījumu veidu, būtu nepieciešamas izmaiņas mikropakalpojumu kodu bāzēs.
Transakciju izsūtne ir dizaina modelis, ko izmanto sadalītās sistēmās, lai nodrošinātu uzticamu ziņojumu izplatīšanu pat neuzticamu ziņojumapmaiņas sistēmu gadījumā. Tas ietver notikumu glabāšanu norādītajā “OutboxEvents” tabulā tajā pašā darījumā, kurā tiek veikta pati operācija. Šī pieeja labi saskan ar relāciju datu bāzu ACID īpašībām. Turpretim daudzas datu bāzes bez SQL pilnībā neatbalsta ACID rekvizītus, tā vietā izvēloties CAP teorēmas un BASE filozofijas principus, kuros prioritāte ir pieejamība un iespējamā konsekvence, nevis stingra konsekvence.
Darījumu izsūtne nodrošina vismaz vienu garantiju , un to var ieviest ar vairākām pieejām:
Darījumu žurnāla astes
Aptauju izdevējs
Darījumu žurnāla slāņošanas pieeja paredz izmantot datu bāzei specifiskus risinājumus, piemēram, CDC (Change Data Capture). Šīs pieejas galvenie trūkumi ir:
Datu bāzēm specifiski risinājumi
Palielināts latentums CDC ieviešanas specifikas dēļ
Vēl viena metode ir Polling Publisher , kas atvieglo izsūtnes izkraušanu, aptaujājot izsūtnes tabulu. Šīs pieejas galvenais trūkums ir iespēja palielināt datubāzes slodzi, kas var radīt lielākas izmaksas. Turklāt ne visas datu bāzes bez SQL atbalsta efektīvu konkrētu dokumentu segmentu vaicāšanu. Tāpēc visu dokumentu izvilkšana var izraisīt veiktspējas pasliktināšanos.
Šeit ir neliela secības diagramma, kas izskaidro, kā tas darbojas.
Transakciju izsūtnes modeļa galvenais izaicinājums ir tā atkarība no datu bāzes ACID īpašībām. Tipiskās OLTP datu bāzēs tas varētu būt vienkārši, taču tas rada problēmas NoSQL jomā. Lai to atrisinātu, potenciāls risinājums ir izmantot pievienošanas žurnālu (piemēram, Kafka) tieši no pieprasījuma apstrādes uzsākšanas.
Tā vietā, lai tieši apstrādātu komandu “iesniegt aizdevuma pieteikumu”, mēs to nekavējoties nosūtām iekšējai Kafka tēmai un pēc tam atgriežam klientam “akceptētu” rezultātu. Tomēr, tā kā ir ļoti iespējams, ka komanda joprojām ir jāapstrādā, mēs nevaram nekavējoties informēt klientu par rezultātu. Lai pārvaldītu šo iespējamo konsekvenci, mēs varam izmantot tādas metodes kā ilgstoša aptauja, klienta iniciēta aptauja, optimistiski lietotāja saskarnes atjauninājumi vai WebSockets vai Server-Sent Events izmantošana paziņojumiem. Tomēr šī ir pavisam atsevišķa tēma, tāpēc atgriezīsimies pie sākotnējās tēmas.
Mēs nosūtījām ziņojumu par iekšējo Kafkas tēmu. Pēc tam aizdevuma pieteikuma pakalpojums izmanto šo ziņojumu — to pašu komandu, ko tas saņēma no klienta — un sāk apstrādi. Pirmkārt, tas izpilda kādu biznesa loģiku; tikai pēc tam, kad šī loģika ir veiksmīgi izpildīta un rezultāti tiek saglabāti, tas publicē jaunus ziņojumus par publisku Kafkas tēmu.
Apskatīsim mazliet pseidokodu.
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(); }
Ko darīt, ja biznesa loģikas apstrāde neizdodas? Neuztraucieties, jo kompensācija vēl nav veikta, ziņojums tiks mēģināts vēlreiz.
Ko darīt, ja jaunu notikumu nosūtīšana Kafkai neizdodas? Neuztraucieties, jo biznesa loģika ir idempota, tāpēc tas neradīs aizdevuma pieteikuma dublikātu. Tā vietā tas mēģinās atkārtoti nosūtīt ziņojumus publiskajai Kafkas tēmai.
Ko darīt, ja ziņojumi tiek nosūtīti Kafkai, bet kompensācijas apņemšanās neizdodas? Neuztraucieties, jo biznesa loģika ir idempota, tāpēc tas neradīs aizdevuma pieteikuma dublikātu. Tā vietā tas atkārtoti nosūtīs ziņojumus publiskajai Kafkas tēmai un cer, ka kompensācijas apņemšanās šoreiz izdosies.
Šīs pieejas galvenie trūkumi ietver papildu sarežģītību, kas saistīta ar jaunu programmēšanas stilu, iespējamo konsekvenci (jo klients uzreiz neuzzinās rezultātu) un prasību, lai visa biznesa loģika būtu idempotenta.
Kas ir notikumu piegāde, un kā to varētu izmantot šeit? Notikumu iegūšana ir programmatūras arhitektūras modelis, ko izmanto, lai modelētu sistēmas stāvokli, tverot visas izmaiņas tās datos kā nemainīgu notikumu virkni. Šie notikumi atspoguļo faktus vai stāvokļa pārejas un kalpo kā vienīgais patiesības avots sistēmas pašreizējam stāvoklim. Tātad tehniski, ieviešot notikumu avotu sistēmu, mums jau ir EventStore visi notikumi, un šo EventStore patērētāji var izmantot kā vienotu patiesības avotu par notikušo. Nav nepieciešams īpašs datu bāzes risinājums, lai izsekotu visas izmaiņas vai bažas par pasūtīšanu, vienīgā problēma ir sēdēšana lasīšanas pusē, jo, lai varētu iegūt faktisko entītijas stāvokli, ir nepieciešams atkārtoti atskaņot visus notikumus.
Šajā rakstā mēs apskatījām vairākas pieejas uzticamas ziņojumapmaiņas izveidei sadalītās sistēmās. Ir vairāki ieteikumi, kurus mēs varētu apsvērt, veidojot sistēmas ar šīm īpašībām
Nākamajā reizē mēs apskatīsim praktiskāku transakciju izsūtnes ieviešanas piemēru. Skat
tu!