Regjistri i shpërndarë për grupet e rrotave: Një përvojë me pëlhurën Hyperledger

Përshëndetje, unë punoj në ekipin e projektit DRD KP (regjistri i shpërndarë i të dhënave për monitorimin e ciklit jetësor të grupeve të rrotave). Këtu dua të ndaj përvojën e ekipit tonë në zhvillimin e një blockchain të ndërmarrjeve për këtë projekt nën kufizimet e teknologjisë. Më së shumti do të flas për pëlhurën Hyperledger, por qasja e përshkruar këtu mund të ekstrapolohet në çdo blockchain të lejuar. Qëllimi përfundimtar i kërkimit tonë është të përgatisim zgjidhje të zinxhirit të ndërmarrjeve në mënyrë që produkti përfundimtar të jetë i këndshëm për t'u përdorur dhe jo shumë i vështirë për t'u ruajtur.

Nuk do të ketë zbulime, zgjidhje të papritura dhe asnjë zhvillim unik nuk do të theksohet këtu (sepse nuk kam asnjë). Unë thjesht dua të ndaj përvojën time modeste, të tregoj se "ishte e mundur" dhe, ndoshta, të lexoj për përvojat e njerëzve të tjerë për marrjen e vendimeve të mira dhe jo aq të mira në komente.

Problemi: Blockchains ende nuk përshkallëzohen

Sot, përpjekjet e shumë zhvilluesve synojnë ta bëjnë blockchain një teknologji vërtet të përshtatshme, dhe jo një bombë me sahat në një mbështjellës të bukur. Kanalet shtetërore, grumbullimi optimist, plazma dhe copëtimi ndoshta do të bëhen të zakonshme. Një ditë. Ose ndoshta TON do të shtyjë përsëri lançimin për gjashtë muaj, dhe Grupi tjetër Plasma do të pushojë së ekzistuari. Ne mund të besojmë në udhërrëfyesin e ardhshëm dhe të lexojmë letra të bardha brilante gjatë natës, por këtu dhe tani duhet të bëjmë diçka me atë që kemi. Bëj mut.

Detyra e vendosur për ekipin tonë në projektin aktual në përgjithësi duket kështu: ka shumë subjekte, që arrijnë në disa mijëra, që nuk duan të ndërtojnë marrëdhënie mbi besimin; Është e nevojshme të ndërtohet një zgjidhje në DLT që do të funksionojë në PC të zakonshëm pa kërkesa të veçanta të performancës dhe do të sigurojë një përvojë përdoruesi jo më të keqe se çdo sistem i centralizuar i kontabilitetit. Teknologjia pas zgjidhjes duhet të minimizojë mundësinë e manipulimit me qëllim të keq të të dhënave - kjo është arsyeja pse blockchain është këtu.

Sloganet nga letrat e bardha dhe mediat na premtojnë se zhvillimi i ardhshëm do të na lejojë të bëjmë miliona transaksione në sekondë. Çfarë është në të vërtetë?

Mainnet Ethereum aktualisht po funksionon me ~30 tps. Vetëm për shkak të kësaj, është e vështirë të perceptohet si blockchain në çfarëdo mënyre të përshtatshme për nevojat e korporatës. Ndër zgjidhjet e lejuara ka standarde që tregojnë 2000 tps (kuorum) ose 3000 tps (Pëlhurë Hyperledger, ka pak më pak në botim, por duhet të keni parasysh që standardi u krye në motorin e vjetër të konsensusit). ishte një përpjekje për përpunimin radikal të pëlhurës, e cila nuk dha rezultatet më të këqija, 20000 tps, por deri tani ky është vetëm një kërkim akademik, në pritje të zbatimit të qëndrueshëm të tij. Nuk ka gjasa që një korporatë që mund të përballojë të mbajë një departament të zhvilluesve të blockchain do të përballojë tregues të tillë. Por problemi nuk është vetëm xhiroja, ka edhe vonesë.

gjendje latente

Vonesa nga momenti i inicimit të një transaksioni deri në miratimin përfundimtar të tij nga sistemi varet jo vetëm nga shpejtësia me të cilën mesazhi kalon nëpër të gjitha fazat e vlefshmërisë dhe renditjes, por edhe nga parametrat e formimit të bllokut. Edhe nëse blockchain-i ynë na lejon të angazhohemi me një shpejtësi prej 1000000 tps, por kërkon 10 minuta për të gjeneruar një bllok 488 MB, a do të bëhet më e lehtë për ne?

Le të hedhim një vështrim më të afërt në ciklin e jetës së transaksionit në Hyperledger Fabric për të kuptuar se ku harxhohet koha dhe si lidhet me parametrat e gjenerimit të bllokut.

Regjistri i shpërndarë për grupet e rrotave: Një përvojë me pëlhurën Hyperledger
marrë nga këtu: hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html#swimlane

(1) Klienti krijon një transaksion, ia dërgon atë kolegëve miratues, këta të fundit simulojnë transaksionin (aplikoni ndryshimet e bëra nga kodi zinxhir në gjendjen aktuale, por mos u angazhoni në librin kryesor) dhe marrin RWSet - emrat, versionet dhe vlerat kryesore marrë nga koleksioni në CouchDB, (2) miratuesit i dërgojnë klientit një RWSet të nënshkruar, (3) klienti ose kontrollon praninë e nënshkrimeve të të gjithë kolegëve të nevojshëm (indosuesit) dhe më pas e dërgon transaksionin te shërbimi i porositjes , ose e dërgon atë pa verifikim (kontrolli do të bëhet akoma më vonë), shërbimi i porositjes formon një bllok dhe (4) ua dërgon të gjithë kolegëve, jo vetëm miratuesve; kolegët kontrollojnë nëse versionet kryesore në grupin e lexuar përputhen me versionet në bazën e të dhënave, që të gjithë miratuesit të kenë nënshkrime, dhe në fund kryejnë bllokimin.

Por kjo nuk është e gjitha. Fjalët "porositësi formon një bllok" fshehin jo vetëm renditjen e transaksioneve, por edhe 3 kërkesa të njëpasnjëshme të rrjetit nga drejtuesi për ndjekësit dhe mbrapa: drejtuesi shton një mesazh në regjistër, ia dërgon ndjekësve, këta të fundit e shtojnë atë. në regjistrin e tyre, dërgon konfirmimin e replikimit të suksesshëm te lideri, lideri kryen mesazhin, dërgon konfirmimin e kryerjes tek ndjekësit, ndjekësit angazhohen. Sa më i vogël të jetë madhësia dhe koha e formimit të bllokut, aq më shpesh shërbimi i porositjes do të duhet të krijojë konsensus. Hyperledger Fabric ka dy parametra për formimin e bllokut: BatchTimeout - koha e formimit të bllokut dhe BatchSize - madhësia e bllokut (numri i transaksioneve dhe madhësia e vetë bllokut në bajt). Sapo njëri prej parametrave të arrijë kufirin, lëshohet një bllok i ri. Sa më shumë nyje të rendit, aq më shumë do të zgjasë. Prandaj, ju duhet të rritni BatchTimeout dhe BatchSize. Por meqenëse RWSet-et janë të versionuara, sa më i madh të jetë blloku që bëjmë, aq më e lartë është gjasat e konflikteve MVCC. Për më tepër, ndërsa BatchTimeout rritet, UX degradon në mënyrë katastrofike. Skema e mëposhtme për zgjidhjen e këtyre problemeve më duket e arsyeshme dhe e qartë.

Si të shmangni pritjen për finalizimin e bllokut dhe të mos humbni aftësinë për të gjurmuar statusin e transaksionit

Sa më e gjatë të jetë koha e formimit dhe madhësia e bllokut, aq më i lartë është xhiroja e zinxhirit të bllokut. Njëra nuk rrjedh drejtpërdrejt nga tjetra, por duhet mbajtur mend se vendosja e konsensusit në RAFT kërkon tre kërkesa rrjeti nga lideri për ndjekësit dhe mbrapa. Sa më shumë nyje të rendit, aq më shumë do të zgjasë. Sa më e vogël të jetë madhësia dhe koha e formimit të bllokut, aq më shumë ndërveprime të tilla janë. Si të rritet koha e gjenerimit dhe madhësia e bllokut pa rritur kohën e përgjigjes së sistemit për përdoruesin përfundimtar?

Së pari, ne duhet të zgjidhim disi konfliktet MVCC të shkaktuara nga një madhësi e madhe blloku, e cila mund të përfshijë RWSet të ndryshme me të njëjtin version. Natyrisht, nga ana e klientit (në lidhje me rrjetin e blockchain, ky mund të jetë fare mirë fundi, dhe dua ta them) ju duhet Trajtuesi i konfliktit MVCC, i cili mund të jetë ose një shërbim i veçantë ose një dekorues i rregullt mbi thirrjen që fillon transaksionin me logjikën e riprovës.

Riprovimi mund të zbatohet me një strategji eksponenciale, por më pas vonesa do të degradojë po aq në mënyrë eksponenciale. Pra, duhet të përdorni ose një riprovim të rastësishëm brenda disa kufijve të vegjël, ose një konstant. Me një sy në përplasjet e mundshme në opsionin e parë.

Hapi tjetër është që ndërveprimi i klientit me sistemin të bëhet asinkron në mënyrë që ai të mos presë 15, 30 ose 10000000 sekonda, të cilat do ta vendosim si BatchTimeout. Por në të njëjtën kohë, është e nevojshme të ruhet aftësia për të verifikuar që ndryshimet e iniciuara nga transaksioni janë/nuk janë regjistruar në blockchain.
Një bazë të dhënash mund të përdoret për të ruajtur statusin e transaksionit. Opsioni më i thjeshtë është CouchDB për shkak të lehtësisë së tij të përdorimit: baza e të dhënave ka një UI jashtë kutisë, një API REST dhe mund të konfiguroni lehtësisht replikimin dhe ndarjen për të. Ju thjesht mund të krijoni një koleksion të veçantë në të njëjtin shembull CouchDB që përdor Fabric për të ruajtur gjendjen e tij botërore. Ne duhet të ruajmë këto lloj dokumentesh.

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

Ky dokument shkruhet në bazën e të dhënave përpara se transaksioni të dërgohet te kolegët, ID-ja e entitetit i kthehet përdoruesit (i njëjti ID përdoret si çelës) nëse ky është një operacion krijimi, dhe më pas fushat Status, TxID dhe Error janë përditësuar pasi informacioni përkatës merret nga kolegët.

Regjistri i shpërndarë për grupet e rrotave: Një përvojë me pëlhurën Hyperledger

Në këtë skemë, përdoruesi nuk pret që blloku të formohet përfundimisht, duke parë rrotën rrotulluese në ekran për 10 sekonda, ai merr një përgjigje të menjëhershme nga sistemi dhe vazhdon të punojë.

Ne zgjodhëm BoltDB për të ruajtur statuset e transaksionit sepse duhet të kursejmë memorie dhe nuk duam të humbim kohë në ndërveprimin e rrjetit me një server të veçantë të bazës së të dhënave, veçanërisht kur ky ndërveprim ndodh duke përdorur një protokoll teksti të thjeshtë. Nga rruga, nëse përdorni CouchDB për të zbatuar skemën e përshkruar më sipër ose thjesht për të ruajtur gjendjen botërore, në çdo rast ka kuptim të optimizoni mënyrën e ruajtjes së të dhënave në CouchDB. Si parazgjedhje, në CouchDB, madhësia e nyjeve b-tree është 1279 bajt, që është shumë më e vogël se madhësia e sektorit në disk, që do të thotë se leximi dhe ribalancimi i pemës do të kërkojnë më shumë qasje fizike në disk. Madhësia optimale korrespondon me standardin Formati i avancuar dhe është 4 kilobajt. Për të optimizuar duhet të vendosim parametrin btree_chunk_size e barabartë me 4096 në skedarin e konfigurimit CouchDB. Për BoltDB një ndërhyrje e tillë manuale nuk kërkohet.

Presioni prapa: strategjia e tamponit

Por mund të ketë shumë mesazhe. Më shumë se sa mund të përballojë sistemi, ndarja e burimeve me një duzinë shërbimesh të tjera përveç atyre të paraqitura në diagram - dhe e gjithë kjo duhet të funksionojë në mënyrë të përsosur edhe në makinat në të cilat ekzekutimi i Intellij Idea do të ishte jashtëzakonisht i lodhshëm.

Problemi i kapaciteteve të ndryshme të sistemeve komunikuese, prodhues dhe konsumator, zgjidhet në mënyra të ndryshme. Le të shohim se çfarë mund të bëjmë.

Tërheqja: Mund të pretendojmë se jemi në gjendje të përpunojmë më së shumti X transaksione në T sekonda. Të gjitha kërkesat që tejkalojnë këtë kufi janë hedhur poshtë. Kjo është mjaft e thjeshtë, por atëherë mund të harroni UX.

Kontrollimi: konsumatori duhet të ketë një lloj ndërfaqe përmes së cilës, në varësi të ngarkesës, ai mund të kontrollojë TPS-në e prodhuesit. Jo keq, por imponon detyrime për zhvilluesit e klientit që krijojnë ngarkesën për të zbatuar këtë ndërfaqe. Kjo është e papranueshme për ne, pasi blockchain në të ardhmen do të integrohet në një numër të madh sistemesh ekzistuese prej kohësh.

buffering: Në vend që të përpiqemi t'i rezistojmë rrjedhës së të dhënave hyrëse, ne mund ta ruajmë këtë transmetim dhe ta përpunojmë atë me shpejtësinë e kërkuar. Natyrisht kjo është zgjidhja më e mirë nëse duam të ofrojmë një përvojë të mirë përdoruesi. Ne implementuam bufferin duke përdorur një radhë në RabbitMQ.

Regjistri i shpërndarë për grupet e rrotave: Një përvojë me pëlhurën Hyperledger

Dy veprime të reja janë shtuar në skemë: (1) pasi të arrijë një kërkesë në API, një mesazh me parametrat e nevojshëm për të thirrur një transaksion vendoset në radhë dhe klienti merr një mesazh që transaksioni është pranuar nga sistemi, (2) backend lexon të dhënat me shpejtësinë e specifikuar në konfigurimin nga radhë; fillon një transaksion dhe përditëson të dhënat në ruajtjen e statusit.
Tani mund të rrisni kohën e formimit dhe të bllokoni kapacitetin aq sa dëshironi, duke fshehur vonesat nga përdoruesi.

Mjete të tjera

Asgjë nuk u tha këtu për kodin zinxhir, sepse, si rregull, nuk ka asgjë për të optimizuar në të. Kodi i zinxhirit duhet të jetë sa më i thjeshtë dhe i sigurt - kjo është gjithçka që kërkohet prej tij. Korniza na ndihmon të shkruajmë kodin zinxhir thjesht dhe në mënyrë të sigurt CCKit nga S7 Techlab dhe analizues statik ringjall^CC.

Përveç kësaj, ekipi ynë po zhvillon një grup shërbimesh për ta bërë punën me Fabric të thjeshtë dhe të këndshme: eksplorues i blockchain, një mjet për ndryshimet automatike të konfigurimit të rrjetit (shtimi/heqja e organizatave, nyjet RAFT), shërbimi për revokimin e certifikatave dhe heqjen e identitetit. Nëse dëshironi të kontribuoni, jeni të mirëpritur.

Përfundim

Kjo qasje ju lejon të zëvendësoni me lehtësi Hyperledger Fabric me Quorum, rrjete të tjera private Ethereum (PoA apo edhe PoW), të zvogëloni ndjeshëm xhiron aktuale, por në të njëjtën kohë të ruani UX normale (si për përdoruesit në shfletues ashtu edhe për sistemet e integruara). Kur zëvendësoni Fabric me Ethereum në skemë, do t'ju duhet vetëm të ndryshoni logjikën e shërbimit/dekoratorit të riprovës nga përpunimi i konflikteve MVCC në rritje dhe ridërgim atomike nonce. Buferimi dhe ruajtja e statusit bënë të mundur shkëputjen e kohës së përgjigjes nga koha e formimit të bllokut. Tani mund të shtoni mijëra nyje porosie dhe të mos keni frikë se blloqet formohen shumë shpesh dhe të ngarkoni shërbimin e porositjes.

Në thelb, kjo është gjithçka që doja të ndaja. Do të jem i lumtur nëse kjo ndihmon dikë në punën e tij.

Burimi: www.habr.com

Shto një koment