Paskirstytas aširačių registras: patirtis naudojant „Hyperledger“ audinį

Sveiki, dirbu projekto DRD KP komandoje (paskirstytas ratų komplektų gyvavimo ciklo stebėjimo duomenų registras). Čia noriu pasidalinti mūsų komandos patirtimi kuriant įmonės blokų grandinę šiam projektui, atsižvelgiant į technologijų apribojimus. Daugiausia kalbėsiu apie „Hyperledger Fabric“, tačiau čia aprašytą metodą galima ekstrapoliuoti bet kuriai leistinai „blockchain“. Galutinis mūsų tyrimo tikslas – parengti įmonės blokų grandinės sprendimus, kad galutinis produktas būtų malonus naudoti ir nebūtų per sunkus jį prižiūrėti.

Čia nebus jokių atradimų, netikėtų sprendimų ir išskirtinių pokyčių (nes aš jų neturiu). Tiesiog noriu pasidalinti savo kuklia patirtimi, parodyti, kad „buvo įmanoma“ ir, galbūt, komentaruose paskaityti apie kitų žmonių patirtį priimant gerus ir nelabai gerus sprendimus.

Problema: Blockchains dar nekeičiamas

Šiandien daugelio kūrėjų pastangos nukreiptos į tai, kad „blockchain“ būtų tikrai patogi technologija, o ne laiko bomba gražiame įpakavime. Būsenos kanalai, optimistinis apibendrinimas, plazma ir skilimas tikriausiai taps įprastu dalyku. Kažkada. O galbūt TON vėl atidės paleidimą šešiems mėnesiams, o kita plazmos grupė nustos egzistuoti. Galime tikėti kitu planu ir naktimis skaityti nuostabias baltas knygas, bet čia ir dabar turime kažką daryti su tuo, ką turime. Padaryk šūdą.

Mūsų komandai dabartiniame projekte iškelta užduotis apskritai atrodo taip: yra daug subjektų, siekiančių kelis tūkstančius, nenorinčių kurti santykių pasitikėjimo pagrindu; Būtina sukurti DLT sprendimą, kuris veiktų įprastuose asmeniniuose kompiuteriuose be specialių našumo reikalavimų ir suteiktų vartotojo patirtį ne prastesnę nei bet kurios centralizuotos apskaitos sistemos. Sprendimo technologija turi iki minimumo sumažinti galimybę piktybiškai manipuliuoti duomenimis – štai kodėl čia yra blokų grandinė.

Baltųjų popierių ir žiniasklaidos šūkiai mums žada, kad kita plėtra leis mums atlikti milijonus operacijų per sekundę. Kas tai iš tikrųjų?

Mainnet Ethereum šiuo metu veikia ~30 tps. Vien dėl to sunku jį suvokti kaip blokų grandinę, tinkančią įmonių poreikiams. Tarp leidžiamų sprendimų yra etalonų, rodančių 2000 tps (Kvorumas) arba 3000 tps („Hyperledger“ audinys, leidinyje yra šiek tiek mažiau, tačiau reikia atsižvelgti į tai, kad etalonas buvo atliktas naudojant senąjį konsensuso variklį). Buvo Bandymas radikaliai apdoroti audinius, kuris davė ne pačius prasčiausius rezultatus, 20000 XNUMX tps, tačiau kol kas tai tik akademinis tyrimas, laukiantis stabilaus savo įgyvendinimo. Mažai tikėtina, kad korporacija, galinti sau leisti išlaikyti blokų grandinės kūrėjų skyrių, taikstytis su tokiais rodikliais. Tačiau problema yra ne tik pralaidumas, bet ir delsa.

Uždelsimas

Vėlavimas nuo operacijos inicijavimo iki galutinio sistemos patvirtinimo priklauso ne tik nuo pranešimo perdavimo per visus patvirtinimo ir užsakymo etapus greičio, bet ir nuo bloko formavimo parametrų. Net jei mūsų blokų grandinė leidžia mums įsipareigoti 1000000 10 488 tps greičiu, bet reikia XNUMX minučių sukurti XNUMX MB bloką, ar mums bus lengviau?

Pažvelkime atidžiau į operacijos gyvavimo ciklą „Hyperledger Fabric“, kad suprastume, kur praleidžiamas laikas ir kaip jis susijęs su blokų generavimo parametrais.

Paskirstytas aširačių registras: patirtis naudojant „Hyperledger“ audinį
paimtas iš čia: hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html#swimlane

(1) Klientas sukuria operaciją, siunčia ją patvirtinantiems bendraamžiams, pastarieji imituoja operaciją (taiko grandinės kodo atliktus pakeitimus esamai būsenai, bet neįsipareigoja knygos) ir gauna RWSet – raktų pavadinimus, versijas ir reikšmes ​​paimta iš CouchDB rinkinio, (2) patvirtintojai siunčia klientui pasirašytą RWSet, (3) klientas patikrina, ar yra visų būtinų partnerių (indoserių) parašų, ir tada siunčia operaciją užsakymo tarnybai. , arba išsiunčia jį be patikrinimo (patikrinimas vis tiek vyks vėliau), užsakymo paslauga suformuoja bloką ir (4) siunčia atgal visiems bendraamžiams, ne tik patvirtintojams; bendraamžiai patikrina, ar skaitymo rinkinio raktų versijos sutampa su duomenų bazės versijomis, ar visi patvirtintojai turi parašus, ir galiausiai įpareigoja bloką.

Bet tai dar ne viskas. Žodžiai „užsakytojas formuoja bloką“ slepia ne tik operacijų eiliškumą, bet ir 3 nuoseklias tinklo užklausas iš lyderio pasekėjams ir atgal: lyderis įtraukia pranešimą į žurnalą, išsiunčia jį sekėjams, pastarasis prideda. į savo žurnalą, siunčia patvirtinimą apie sėkmingą replikaciją lyderiui, lyderis įsipareigoja pranešimą, siunčia patvirtinimą pasekėjams, sekėjai įsipareigoja. Kuo mažesnis bloko dydis ir sudarymo laikas, tuo dažniau užsakymo tarnyba turės pasiekti konsensusą. „Hyperledger Fabric“ turi du bloko formavimo parametrus: BatchTimeout – bloko formavimo laikas ir BatchSize – bloko dydis (operacijų skaičius ir paties bloko dydis baitais). Kai tik vienas iš parametrų pasiekia ribą, išleidžiamas naujas blokas. Kuo daugiau užsakymo mazgų, tuo ilgiau tai užtruks. Todėl reikia padidinti BatchTimeout ir BatchSize. Tačiau kadangi RWSets yra versijos, kuo didesnį bloką sukuriame, tuo didesnė MVCC konfliktų tikimybė. Be to, didėjant BatchTimeout, UX katastrofiškai blogėja. Šių problemų sprendimo schema man atrodo pagrįsta ir akivaizdi.

Kaip nelaukti bloko užbaigimo ir neprarasti galimybės sekti operacijos būseną

Kuo ilgesnis formavimo laikas ir bloko dydis, tuo didesnis blokų grandinės pralaidumas. Vienas iš jų tiesiogiai neišplaukia iš kito, tačiau reikia atsiminti, kad norint pasiekti konsensusą RAFT, reikia trijų tinklo užklausų iš lyderio pasekėjams ir atgal. Kuo daugiau užsakymo mazgų, tuo ilgiau tai užtruks. Kuo mažesnis bloko formavimosi dydis ir laikas, tuo daugiau tokių sąveikų. Kaip padidinti generavimo laiką ir bloko dydį nepadidinant sistemos reakcijos laiko galutiniam vartotojui?

Pirma, turime kažkaip išspręsti MVCC konfliktus, kuriuos sukelia didelis bloko dydis, kuriame gali būti skirtingų RWSetų su ta pačia versija. Akivaizdu, kad iš kliento pusės (kalbant apie blokų grandinės tinklą, tai gali būti užpakalinė programa, ir aš tai turiu omenyje) jums reikia MVCC konfliktų tvarkytojas, kuri gali būti atskira paslauga arba įprastas dekoratorius virš skambučio, kuris inicijuoja operaciją su pakartotinio bandymo logika.

Pakartotinis bandymas gali būti įgyvendintas naudojant eksponentinę strategiją, bet tada vėlavimas sumažės taip pat eksponentiškai. Taigi turėtumėte naudoti atsitiktinių imčių pakartotinį bandymą tam tikrose nedidelėse ribose arba nuolatinį bandymą. Atsižvelgiant į galimus susidūrimus pirmame variante.

Kitas žingsnis – kliento sąveiką su sistema paversti asinchronine, kad ji nelauktų 15, 30 ar 10000000 sekundžių, kurias nustatysime kaip BatchTimeout. Tačiau tuo pačiu būtina išlaikyti galimybę patikrinti, ar sandorio inicijuoti pakeitimai yra/nėra įrašyti blokų grandinėje.
Duomenų bazė gali būti naudojama sandorio būsenai saugoti. Paprasčiausias pasirinkimas yra CouchDB dėl naudojimo paprastumo: duomenų bazėje yra vartotojo sąsaja, REST API ir galite lengvai nustatyti jos replikaciją ir dalijimąsi. Galite tiesiog sukurti atskirą kolekciją tame pačiame CouchDB egzemplioriuje, kuris naudoja Fabric savo pasaulinei būsenai saugoti. Turime saugoti tokio tipo dokumentus.

{
 Status string // Статус транзакции: "pending", "done", "failed"
 TxID: string // ID транзакции
 Error: string // optional, сообщение об ошибке
}

Šis dokumentas įrašomas į duomenų bazę prieš išsiunčiant transakciją bendraamžiams, subjekto ID grąžinamas vartotojui (tas pats ID naudojamas kaip raktas), jei tai yra kūrimo operacija, tada bus rodomi laukai Būsena, TxID ir Klaida. atnaujinama, kai atitinkama informacija gaunama iš bendraamžių.

Paskirstytas aširačių registras: patirtis naudojant „Hyperledger“ audinį

Pagal šią schemą vartotojas nelaukia, kol pagaliau susiformuos blokas, 10 sekundžių stebėdamas besisukantį ratą ekrane, gauna momentinį atsakymą iš sistemos ir toliau dirba.

Operacijų būsenoms saugoti pasirinkome BoltDB, nes turime taupyti atmintį ir nenorime gaišti laiko tinklo sąveikai su atskiru duomenų bazės serveriu, ypač kai ši sąveika vyksta naudojant paprasto teksto protokolą. Beje, nesvarbu, ar naudojate CouchDB aukščiau aprašytai schemai įgyvendinti, ar tiesiog pasaulio būsenai išsaugoti, bet kuriuo atveju prasminga optimizuoti duomenų saugojimo būdą CouchDB. Pagal numatytuosius nustatymus „CouchDB“ b-medžio mazgų dydis yra 1279 baitai, o tai yra daug mažesnis už sektoriaus dydį diske, o tai reiškia, kad tiek nuskaityti, tiek subalansuoti medį reikės daugiau fizinės prieigos prie disko. Optimalus dydis atitinka standartą Išplėstinis formatas ir yra 4 kilobaitai. Norėdami optimizuoti, turime nustatyti parametrą btree_chunk_size lygus 4096 CouchDB konfigūracijos faile. Dėl BoltDB toks rankinis įsikišimas nereikalauja.

Priešslėgis: buferio strategija

Tačiau žinučių gali būti daug. Daugiau nei gali valdyti sistema, dalintis ištekliais su keliolika kitų paslaugų, be tų, kurios parodytos diagramoje – ir visa tai turėtų veikti nepriekaištingai net ir įrenginiuose, kuriuose „Intellij Idea“ paleidimas būtų labai varginantis.

Skirtingo ryšio sistemų, gamintojo ir vartotojo, pajėgumo problema sprendžiama įvairiai. Pažiūrėkime, ką galime padaryti.

Mesti: Galime tvirtinti, kad galime apdoroti daugiausia X operacijų per T sekundes. Visos užklausos, viršijančios šį limitą, yra atmetamos. Tai gana paprasta, bet tada galite pamiršti apie UX.

kontroliavimas: vartotojas turi turėti kažkokią sąsają, per kurią, priklausomai nuo apkrovos, galėtų valdyti gamintojo TPS. Neblogai, bet apkrovą kuriančio kliento kūrėjams tai įpareigoja diegti šią sąsają. Mums tai nepriimtina, nes „blockchain“ ateityje bus integruota į daugybę seniai egzistuojančių sistemų.

Buferizavimas: Užuot bandę atsispirti įvesties duomenų srautui, galime šį srautą buferizuoti ir apdoroti reikiamu greičiu. Akivaizdu, kad tai yra geriausias sprendimas, jei norime suteikti gerą vartotojo patirtį. Įdiegėme buferį naudodami eilę RabbitMQ.

Paskirstytas aširačių registras: patirtis naudojant „Hyperledger“ audinį

Į schemą buvo įtraukti du nauji veiksmai: (1) gavus užklausą API, į eilę patalpinamas pranešimas su parametrais, reikalingais operacijai iškviesti, ir klientas gauna pranešimą, kad sandoris priimtas sistema, (2) backend nuskaito duomenis konfigūracijoje nurodytu greičiu iš eilės; inicijuoja operaciją ir atnaujina duomenis būsenos saugykloje.
Dabar galite kiek norite padidinti formavimo laiką ir blokuoti pajėgumus, slėpdami delsą nuo vartotojo.

Kiti įrankiai

Čia nieko nebuvo pasakyta apie grandininį kodą, nes, kaip taisyklė, jame nėra ką optimizuoti. Grandininis kodas turi būti kuo paprastesnis ir saugesnis – tai viskas, ko iš jo reikalaujama. Sistema padeda mums paprastai ir saugiai parašyti grandinės kodą CCKit iš S7 Techlab ir statinio analizatoriaus atgaivinti^CC.

Be to, mūsų komanda kuria paslaugų rinkinį, kad darbas su Fabric būtų paprastas ir malonus: blockchain tyrinėtojas, įrankis, skirtas automatiniai tinklo konfigūracijos pakeitimai (organizacijų pridėjimas / pašalinimas, RAFT mazgai), įrankis, skirtas sertifikatų panaikinimas ir tapatybės panaikinimas. Jei norite prisidėti, esate laukiami.

išvada

Šis metodas leidžia lengvai pakeisti „Hyperledger Fabric“ „Quorum“, kitais privačiais „Ethereum“ tinklais (PoA ar net PoW), žymiai sumažinti faktinį pralaidumą, bet tuo pačiu išlaikyti įprastą UX (tiek naudotojams naršyklėje, tiek integruotoms sistemoms). Keičiant Fabric į Ethereum schemoje, jums reikės pakeisti tik pakartotinio bandymo paslaugos / dekoratoriaus logiką iš MVCC konfliktų apdorojimo į atominį padidėjimą ir pakartotinį siuntimą. Buferis ir būsenos saugojimas leido atsieti reakcijos laiką nuo bloko formavimo laiko. Dabar galite pridėti tūkstančius užsakymų mazgų ir nesibaiminti, kad blokai formuojasi per dažnai ir apkrauti užsakymo paslaugą.

Iš esmės tai viskas, kuo norėjau pasidalinti. Džiaugiuosi, jei tai padės kam nors jų darbe.

Šaltinis: www.habr.com

Добавить комментарий