Distribueret Registry for Wheelsets: En oplevelse med Hyperledger Fabric

Hej, jeg arbejder i teamet af DRD KP-projektet (distribueret dataregister til overvågning af livscyklus for hjulsæt). Her vil jeg gerne dele vores teams erfaring med at udvikle en virksomheds blockchain til dette projekt under teknologiens begrænsninger. For det meste vil jeg tale om Hyperledger Fabric, men tilgangen beskrevet her kan ekstrapoleres til enhver tilladt blockchain. Det ultimative mål med vores forskning er at forberede enterprise blockchain-løsninger på en sådan måde, at det endelige produkt er behageligt at bruge og ikke for svært at vedligeholde.

Der vil ikke være opdagelser, uventede løsninger, og ingen unikke udviklinger vil blive dækket her (fordi jeg ikke har dem). Jeg vil bare dele min ydmyge erfaring, vise at "det var muligt" og måske læse om andres erfaringer med at træffe gode og knap så gode beslutninger i kommentarerne.

Problem: blockchains er endnu ikke skalerbare

I dag er indsatsen fra mange udviklere rettet mod at gøre blockchain til en virkelig bekvem teknologi, og ikke en tikkende bombe i en smuk indpakning. Statskanaler, optimistisk rollup, plasma og sharding kan blive almindelige. En skønne dag. Eller måske vil TON igen udskyde lanceringen i seks måneder, og den næste Plasma Group ophører med at eksistere. Vi kan tro på en anden køreplan og læse strålende hvidbøger om natten, men her og nu skal vi gøre noget med det, vi har. Få lort gjort.

Opgaven, som er tildelt vores team i det aktuelle projekt, ser sådan her ud i generelle vendinger: Der er mange fag, der når flere tusinde, som ikke ønsker at bygge relationer på tillid; det er nødvendigt at bygge på DLT en løsning, der fungerer på almindelige pc'er uden særlige krav til ydeevne og giver en brugeroplevelse, der ikke er værre end et hvilket som helst centraliseret regnskabssystem. Teknologien bag løsningen skal minimere muligheden for ondsindet datamanipulation – og derfor er blockchain her.

Slogans fra hvidbøger og medier lover os, at den næste udvikling vil tillade millioner af transaktioner i sekundet. Hvad er det egentlig?

Mainnet Ethereum kører i øjeblikket ved ~30 tps. Alene på grund af dette er det svært at opfatte det som en blockchain, der på nogen måde er egnet til virksomhedernes behov. Blandt de tilladte løsninger kendes benchmarks, der viser 2000 tps (Beslutningsdygtighed) eller 3000 tps (Hyperledger Fabric, der er lidt mindre i publikationen, men husk på, at benchmark blev udført på den gamle konsensusmotor). var et forsøg på radikalt at omarbejde Fabric, som ikke gav de værste resultater, 20000 tps, men indtil videre er det kun akademiske undersøgelser, der venter på deres stabile implementering. Det er usandsynligt, at et selskab, der har råd til at opretholde en afdeling af blockchain-udviklere, vil finde sig i sådanne indikatorer. Men problemet er ikke kun i gennemløb, der er også latency.

Latency

Forsinkelsen fra det øjeblik en transaktion påbegyndes til dens endelige godkendelse af systemet afhænger ikke kun af hastigheden af ​​meddelelsen, der passerer gennem alle stadier af validering og bestilling, men også af blokdannelsesparametrene. Selvom vores blockchain giver os mulighed for at forpligte os ved 1000000 tps, men det tager 10 minutter at danne en 488 MB blok, bliver det så nemmere for os?

Lad os se nærmere på livscyklussen for en transaktion i Hyperledger Fabric for at forstå, hvad der tager tid, og hvordan det relaterer til blokdannelsesparametre.

Distribueret Registry for Wheelsets: En oplevelse med Hyperledger Fabric
taget herfra: hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html#swimlane

(1) Klienten danner en transaktion, sender den til godkendte peers, sidstnævnte simulerer transaktionen (anvend ændringerne foretaget af kædekoden til den aktuelle tilstand, men forpligt dig ikke til hovedbogen) og modtager RWSet - nøglenavne, versioner og værdier taget fra samlingen i CouchDB, (2) endorsers sender et underskrevet RWSet tilbage til klienten, (3) klienten enten tjekker for signaturerne fra alle de nødvendige peers (endorsers), og sender derefter transaktionen til ordren service, eller sender den uden verifikation (verifikationen vil stadig finde sted senere), bestillingsservicen danner en blok og ( 4) sender tilbage til alle peers, ikke kun endorsers; Peers kontrollerer, at versionerne af nøglerne i læsesættet matcher versionerne i databasen, signaturerne fra alle endorsers, og begår til sidst blokeringen.

Men det er ikke alt. Bag ordene "bestiller danner en blok" gemmer sig ikke kun bestilling af transaktioner, men også 3 på hinanden følgende netværksanmodninger fra lederen til følgere og tilbage: lederen tilføjer en besked til loggen, sender til følgerne, sidstnævnte tilføjer til deres log, send bekræftelse på vellykket replikering til lederen, lederen begår beskeden, sender commit-bekræftelse til følgere, følgere commit. Jo mindre blokstørrelse og tid er, jo oftere skal bestillingstjenesten etablere konsensus. Hyperledger Fabric har to blokdannelsesparametre: BatchTimeout - blokdannelsestid og BatchSize - blokstørrelse (antallet af transaktioner og størrelsen af ​​selve blokken i bytes). Så snart en af ​​parametrene når grænsen, udsendes en ny blok. Jo flere bestiller-noder, jo længere tid vil dette tage. Derfor skal du øge BatchTimeout og BatchSize. Men da RWSets er versionerede, jo større vi gør blokken, jo højere er sandsynligheden for MVCC-konflikter. Derudover forringes UX katastrofalt med en stigning i BatchTimeout. Det forekommer mig rimeligt og indlysende følgende skema til løsning af disse problemer.

Sådan undgår du at vente på blokafslutning og ikke miste overblikket over transaktionsstatus

Jo længere dannelsestiden og blokstørrelsen er, desto højere er gennemløbet af blockchain. Det ene følger ikke direkte af det andet, men det skal huskes, at etablering af konsensus i RAFT kræver tre netværksanmodninger fra lederen til følgerne og tilbage. Jo flere ordrenoder, jo længere tid vil det tage. Jo mindre størrelsen og tidspunktet for blokdannelse er, jo flere sådanne interaktioner. Hvordan øger man dannelsestiden og blokstørrelsen uden at øge systemets responstid for slutbrugeren?

Først skal du på en eller anden måde løse MVCC-konflikter forårsaget af en stor blokstørrelse, som kan omfatte forskellige RWSets med den samme version. Det er klart, på klientsiden (i forhold til blockchain-netværket kan dette godt være en backend, og jeg mener det) MVCC konflikthåndtering, som enten kan være en separat tjeneste eller en almindelig dekoratør over et transaktionsinitierende opkald med genforsøgslogik.

Genforsøg kan implementeres med en eksponentiel strategi, men så vil latenstiden også forringes eksponentielt. Så du bør bruge enten et randomiseret genforsøg inden for visse små grænser eller et konstant. Med øje for mulige kollisioner i den første variant.

Næste trin er at gøre klientens interaktion med systemet asynkron, så den ikke venter i 15, 30 eller 10000000 sekunder, som vi indstiller som BatchTimeout. Men samtidig er det nødvendigt at bevare muligheden for at sikre, at de ændringer, som transaktionen igangsætter, registreres/ikke registreres i blockchainen.
En database kan bruges til at gemme status for transaktioner. Den nemmeste mulighed er CouchDB på grund af dens brugervenlighed: databasen har en UI ud af kassen, en REST API, og du kan nemt konfigurere replikering og sharding til den. Du kan bare oprette en separat samling i den samme CouchDB-instans, som Fabric bruger til at gemme sin verdenstilstand. Vi skal opbevare sådanne dokumenter.

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

Dette dokument skrives til databasen, før transaktionen sendes til peers, enheds-id'et returneres til brugeren (det samme id bruges som en nøgle), hvis dette er en oprettelseshandling, og derefter er felterne Status, TxID og Error opdateret i takt med, at der modtages relevant information fra peers.

Distribueret Registry for Wheelsets: En oplevelse med Hyperledger Fabric

I denne ordning venter brugeren ikke på, at blokken endelig bliver dannet, ser det drejende hjul på skærmen i 10 sekunder, han modtager et øjeblikkeligt svar fra systemet og fortsætter med at arbejde.

Vi valgte BoltDB til at gemme transaktionsstatusser, fordi vi har brug for at spare hukommelse og ikke ønsker at spilde tid på netværksinteraktion med en selvstændig databaseserver, især når denne interaktion finder sted ved hjælp af almindelig tekst-protokollen. Forresten, uanset om du bruger CouchDB til at implementere det ovenfor beskrevne skema eller blot til at gemme verdenstilstanden, giver det under alle omstændigheder mening at optimere den måde, data gemmes i CouchDB. Som standard i CouchDB er størrelsen af ​​b-tree noder 1279 bytes, hvilket er meget mindre end sektorstørrelsen på disken, hvilket betyder, at både læsning og rebalancering af træet vil kræve flere fysiske diskadgange. Den optimale størrelse opfylder standarden Avanceret format og er 4 kilobyte. For optimering skal vi indstille parameteren btree_chunk_size lig med 4096 i CouchDB-konfigurationsfilen. For BoltDB en sådan manuel indgriben ikke påkrævet.

Modtryk: bufferstrategi

Men der kan være mange beskeder. Mere end systemet kan håndtere, deler ressourcer med et dusin andre tjenester udover dem, der er vist i diagrammet - og alt dette burde fungere fejlfrit selv på maskiner, hvor det ville være ekstremt kedeligt at køre Intellij Idea.

Problemet med forskellig gennemstrømning af kommunikationssystemer, producent og forbruger, løses på forskellige måder. Lad os se, hvad vi kan gøre.

Dropper: vi kan hævde at kunne behandle højst X transaktioner på T sekunder. Alle anmodninger, der overskrider denne grænse, slettes. Det er ret simpelt, men så kan du glemme UX.

Styring: Forbrugeren skal have en eller anden grænseflade, hvorigennem han, afhængigt af belastningen, kan styre producentens tps. Ikke dårligt, men det pålægger udviklerne af belastningsklienten en forpligtelse til at implementere denne grænseflade. For os er dette uacceptabelt, da blockchain i fremtiden vil blive integreret i en lang række af længe eksisterende systemer.

buffering: i stedet for at forsøge at modstå inputdatastrømmen, kan vi buffer denne strøm og behandle den med den nødvendige hastighed. Dette er naturligvis den bedste løsning, hvis vi ønsker at give en god brugeroplevelse. Vi implementerede bufferen ved hjælp af en kø i RabbitMQ.

Distribueret Registry for Wheelsets: En oplevelse med Hyperledger Fabric

To nye handlinger er blevet tilføjet til skemaet: (1) efter at en API-anmodning er modtaget, sættes en besked i kø med de nødvendige parametre for at kalde transaktionen, og klienten modtager en besked om, at transaktionen er blevet accepteret af systemet, ( 2) backend læser data med en hastighed specificeret i konfigurationen fra køen; starter en transaktion og opdaterer dataene i statuslageret.
Nu kan du øge byggetiden og blokere kapaciteten, så meget du vil, og skjule forsinkelser fra brugeren.

Andre værktøjer

Her blev der ikke sagt noget om kædekode, for der er normalt ikke noget at optimere i det. Kædekoden skal være så enkel og sikker som muligt - det er alt, der kræves af den. Rammerne hjælper os meget med at skrive kædekode enkelt og sikkert. CSKit fra S7 Techlab og statisk analysator genoplive^CC.

Derudover er vores team ved at udvikle et sæt hjælpeprogrammer for at gøre arbejdet med Fabric enkelt og behageligt: blockchain explorer, nytte til automatisk netværksrekonfiguration (tilføj/fjern organisationer, RAFT noder), værktøj til certifikattilbagekaldelse og identitetsfjernelse. Hvis du har lyst til at bidrage, er du velkommen.

Konklusion

Denne tilgang gør det nemt at erstatte Hyperledger Fabric med Quorum, andre private Ethereum-netværk (PoA eller endda PoW), reducerer den reelle gennemstrømning markant, men opretholder samtidig normal UX (både for brugere i browseren og fra siden af ​​integrerede systemer). ). Når du udskifter stof med Ethereum i ordningen, er det kun logikken i genforsøgstjenesten/dekoratøren, der skal ændres fra at håndtere MVCC-konflikter til en atomisk nonce-stigning og genafsendelse. Buffer og statuslagring gjorde det muligt at afkoble responstiden fra blokdannelsestiden. Nu kan du tilføje tusindvis af ordrenoder og ikke være bange for, at der dannes blokke for ofte og indlæser bestillingstjenesten.

Generelt er dette alt, hvad jeg ønskede at dele. Jeg vil blive glad, hvis det hjælper nogen i deres arbejde.

Kilde: www.habr.com

Tilføj en kommentar