Blockchain — inovatívna technológia, ktorá sľubuje zlepšiť mnohé oblasti ľudskeho života. Prenáša reálne procesy a produkty do digitálneho priestoru, zabezpečuje rýchlosť a spoľahlivosť finančných operácií, znižuje ich náklady a tiež umožňuje vytvárať moderné DAPP aplikácie s využitím inteligentných zmlúv v decentralizovaných sieťach.
Pri zohľadnení mnohých výhod a rozmanitých oblastí aplikácie blockchainu, sa môže zdať zvláštne, že táto sľubná technológia ešte neprenikla do všetkých odvetví. Problém spočíva v tom, že súčasným decentralizovaným blockchainom chýba škálovateľnosť. Ethereum spracúva približne 20 transakcií za sekundu, čo nestačí na uspokojenie potrieb súčasného dynamického podnikania. Zároveň sa firmy využívajúce technológiu blockchainu neodvážia vzdať sa Etherea kvôli jeho vysokej úrovni ochrany pred hackingom a poruchami siete.
Aby sa zabezpečila decentralizácia, bezpečnosť a škálovateľnosť v blockchain, čím sa rieši Trilema škálovateľnosti, tím vývojárov vytvoril Plasma Cash — dcérsku reťazec pozostávajúcu zo smart kontraktu a súkromnej siete založenej na Node.js, ktorá periodicky prenáša svoj stav do hlavnej reťaze (Ethereum).

Kľúčové procesy v Plasma Cash
1. Používateľ vyvolá funkciu smart kontraktu `deposit`, pričom do nej posiela sumu v ETH, ktorú chce umiestniť do tokenu Plasma Cash. Funkcia smart kontraktu vytvorí token a generuje udalosť o tom.
2. Plasma Cash uzly, ktoré sú prihlásené na odber udalostí smart kontraktu, prijímajú udalosť o vytvorení vkladu a pridávajú do poolu transakciu o vytvorení tokenu.
3. Periodicky špeciálne uzly Plasma Cash vezmú všetky transakcie z poolu (až do 1 milióna) a vytvoria z nich blok, vypočítajú Merkleho strom a následne hash. Tento blok je odoslaný ďalším uzlom na overenie. Uzly kontrolujú, či je hash Merkle platný, či sú transakcie platné (napríklad, či je odosielateľ tokenu jeho vlastníkom). Po overení bloku uzol vyvolá funkciu `submitBlock` smart kontraktu, ktorá ukladá do hlavnej reťaze číslo a hash Merkle bloku. Smart kontrakt generuje udalosť o úspešnom pridaní bloku. Transakcie sú odstránené z poolu.
4. Uzly, ktoré dostali udalosť o odoslaní bloku, začínajú aplikovať transakcie, ktoré boli pridané do bloku.
5. V určitom momente chce vlastník (alebo nevlastník) tokenu vybrať ho z Plasma Cash. Na to volá funkciu `startExit`, pričom jej odovzdáva informácie o posledných 2 transakciách tokenu, ktoré potvrdzujú, že je jeho vlastníkom. Smart kontrakt, využívajúc hash Merkle, overuje prítomnosť transakcií v blokoch a odosiela token na výber, ktorý sa uskutoční za dve týždne.
6. Ak došlo k porušeniam pri výbere tokenu (token bol minúť po začatí procedúry výberu alebo token bol už pred výberom cudzí), vlastník tokenu môže odvolať výber v priebehu dvoch týždňov.

Súkromnosť sa dosahuje dvoma spôsobmi
1. Hlavný reťazec nič nevie o transakciách, ktoré sa formujú a posielajú v rámci podradného reťazca. Verejnou zostáva informácia o tom, kto vložil a vybral ETH do/z Plasma Cash.
2. Podradený reťazec umožňuje organizovať anonymné transakcie s využitím zk-SNARKs.
Technologický stack
- NodeJS
- Kľuč-hodnota
- Etherium
- Soild
Testovanie
Pri vývoji Plasma Cash sme otestovali rýchlosť fungovania systému a získali nasledujúce výsledky:
- do 35 000 transakcií za sekundu sa pridáva do mraku;
- do 1 000 000 transakcií môže byť uložených v bloku.
Testy sa vykonávali na 3 nasledovných serveroch:
1. Intel Core i7-6700 Quad-Core Skylake s NVMe SSD — 512 GB, 64 GB DDR4 RAM
Boli nasadené 3 validujúce uzly Plasma Cash.
2. AMD Ryzen 7 1700X Octa-Core 'Summit Ridge' (Zen), SATA SSD — 500 GB, 64 GB DDR4 RAM
Bola vybudovaná Ropsten testnet ETH uzol.
Boli nasadené 3 validujúce uzly Plasma Cash.
3. Intel Core i9-9900K Octa-Core s NVMe SSD — 1 TB, 64 GB DDR4 RAM
Bola vytvorená 1 odosielacia uzol Plasma Cash.
Boli nasadené 3 validujúce uzly Plasma Cash.
Prebiehal test na pridávanie transakcií do siete Plasma Cash.
Celkovo: 10 uzlov Plasma Cash v súkromnej sieti.
Test 1
Existuje limit na 1 milión transakcií v bloku. Preto 1 milión transakcií sa nachádza v 2 blokoch (keďže systém stihne zobrať časť transakcií a odoslať ich, kým sú ešte odosielané).

Počiatocný stav: posledný blok #7; v databáze je uložených 1 milión transakcií a tokenov.
00:00 — spustenie skriptu generovania transakcií
01:37 — vytvorených 1 milión transakcií a začalo sa odosielanie do uzla
01:46 — odosielacia uzol vzala z mraku 240k transakcií a formuje blok #8. Tiež vidíme, že sa do mraku pridáva 320k transakcií za 10 sekúnd
01:58 — blok #8 je podpísaný a odoslaný na validáciu
02:03 — blok #8 bol validovaný a bola vyvolaná funkcia `submitBlock` smart kontraktu s hashom Merkle a číslom bloku
02:10 — demo skript prestal fungovať, ktorý odoslal 1 milión transakcií za 32 sekúnd
02:33 — uzly začali prijímať informácie o tom, že blok #8 bol pridaný do koreňového reťazca a začali vykonávať 240 000 transakcií
02:40 — z poolu bolo odstránených 240 000 transakcií, ktoré sú už v bloku #8
02:56 — submit uzol vzal z poolu zostávajúce 760 000 transakcií a začal počítať hash Merkle a podpisovať blok #9
03:20 — všetky uzly obsahujú 1 milión 240 000 transakcií a tokenov
03:35 — blok #9 bol podpísaný a odoslaný na validáciu iným uzlom
03:41 — došlo k chybe siete
04:40 — podľa timeoutu prestalo očakávanie na validáciu bloku #9
04:54 — submit uzol vzal z poolu zostávajúce 760 000 transakcií a začal počítať hash Merkle a podpisovať blok #9
05:32 — blok #9 bol podpísaný a odoslaný na validáciu iným uzlom
05:53 — blok #9 bol validovaný a odoslaný do koreňového reťazca
06:17 — uzly začali prijímať informácie o tom, že blok #9 bol pridaný do koreňového reťazca a začali vykonávať 760 000 transakcií
06:47 — pool sa vyčistil od transakcií, ktoré sú v bloku #9
09:06 — všetky uzly obsahujú 2 milióny transakcií a tokenov
Test 2
Existuje limit 350 000 na blok. Výsledkom je 3 bloky.

Počiatočný stav: posledný blok #9; v databáze je uložených 2 milióny transakcií a tokenov
00:00 — skript na generáciu transakcií už beží
00:44 — bolo vytvorených 1 milión transakcií a začalo sa odosielanie do uzla
00:56 — submit uzol vzal z poolu 320 000 transakcií a vytvára blok #10. Taktiež vidíme, že do poolu pribúda 320 000 transakcií za 10 sekúnd
01:12 — blok #10 bol podpísaný a odoslaný iným uzlom na validáciu
01:18 — demo skript prestal fungovať, ktorý odoslal 1 milión transakcií za 34 sekúnd
01:20 — blok #10 bol validovaný a odoslaný do koreňového reťazca
01:51 — všetky uzly získali zo koreňového reťazca informácie o tom, že blok #10 bol pridaný, a začínajú aplikovať 320 000 transakcií
02:01 — pool sa vyčistil na 320 000 transakcií, ktoré boli pridané do bloku #10
02:15 — submit uzol vzal z poolu 350 000 transakcií a vytvára blok #11
02:34 — blok #11 bol podpísaný a odoslaný iným uzlom na validáciu
02:51 — blok #11 bol validovaný a odoslaný do koreňového reťazca
02:55 — posledný uzol vykonal transakcie z bloku #10
10:59 — veľmi dlhá transakcia s odoslaním bloku #9 prebiehala v koreňovom reťazci, ale nakoniec bola úspešná a všetky uzly dostali informáciu a začali vykonávať 350k transakcií.
11:05 — táto čistička sa zbavila 320k transakcií, ktoré boli pridané do bloku #11.
12:10 — všetky uzly obsahujú 1 milión 670k transakcií a tokenov.
12:17 — uzol odoslania prevzal z poolu 330k transakcií a formuje blok #12.
12:32 — blok #12 bol podpísaný a odoslaný ostatným uzlom na overenie.
12:39 — blok #12 bol overený a odoslaný do koreňového reťazca.
13:44 — všetky uzly dostali z koreňového reťazca informáciu, že blok #12 bol pridaný a začínajú aplikovať 330k transakcií.
14:50 — všetky uzly obsahujú 2 milióny transakcií a tokenov.
Test 3
Na prvom a druhom serveri bola jedna validačná uzol vymenená za uzol odoslania.

Počiatočný stav: posledný blok #84; v databáze je uložených 0 transakcií a tokenov.
00:00 — Spustili sa 3 skripty, ktoré generujú a posielajú po 1 milión transakcií.
01:38 — vytvorených 1 milión transakcií a začala sa odosielať do uzla odoslania #3.
01:50 — uzol odoslania #3 prevzal z poolu 330k transakcií a formuje blok #85 (f21). Vidíme tiež, že do poolu bolo pridaných 350k transakcií za 10 sekúnd.
01:53 — vytvorených 1 milión transakcií a začala sa odosielať do uzla odoslania #1.
01:50 — uzol odoslania #3 prevzal z poolu 330k transakcií a formuje blok #85 (f21). Vidíme tiež, že do poolu bolo pridaných 350k transakcií za 10 sekúnd.
02:01 — uzol odoslania #1 prevzal z poolu 250k transakcií a formuje blok #85 (65e).
02:06 — blok #85 (f21) bol podpísaný a odoslaný ostatným uzlom na overenie.
02:08 — skončil sa demo-skript servera #3, ktorý odoslal 1 milión transakcií za 30 sekúnd.
02:14 — blok #85 (f21) bol overený a odoslaný do koreňového reťazca.
02:19 — blok #85 (65e) bol podpísaný a odoslaný ostatným uzlom na overenie.
02:22 — vytvorených 1 milión transakcií a začala sa odosielať do uzla odoslania #2.
02:27 — blok #85 (65e) bol overený a odoslaný do koreňového reťazca.
02:29 — uzol odoslania #2 prevzal z poolu 111855 transakcií a formuje blok #85 (256).
02:36 — blok #85 (256) bol podpísaný a odoslaný ostatným uzlom na overenie.
02:36 — skončil sa demo-skript servera #1, ktorý odoslal 1 milión transakcií za 42.5 sekundy.
02:38 — blok #85 (256) bol overený a odoslaný do koreňového reťazca.
03:08 — skončil sa demo-skript servera #2, ktorý odoslal 1 milión transakcií za 47 sekúnd.
03:38 — všetky uzly dostali z koreňového reťazca informáciu, že bloky #85 (f21), #86(65e), #87(256) boli pridané a začínajú aplikovať 330k, 250k, 111855 transakcií.
03:49 — pool sa vyčistil o 330k, 250k, 111855 transakcií, ktoré boli pridané do blokov #85 (f21), #86(65e), #87(256)
03:59 — submit uzol #1 vzal z poolu 888145 transakcií a formuje blok #88 (214), submit uzol #2 vzal z poolu 750k transakcií a formuje blok #88 (50a), submit uzol #3 vzal z poolu 670k transakcií a formuje blok #88 (d3b)
04:44 — blok #88 (d3b) bol podpísaný a poslaný iným uzlom na validáciu
04:58 — blok #88 (214) bol podpísaný a poslaný iným uzlom na validáciu
05:11 — blok #88 (50a) bol podpísaný a poslaný iným uzlom na validáciu
05:11 — blok #85 (d3b) bol validovaný a poslaný do koreňového reťazca
05:36 — blok #85 (214) bol validovaný a poslaný do koreňového reťazca
05:43 — všetky uzly dostali z koreňového reťazca informácie o tom, že bloky #88 (d3b), #89(214) boli pridané a začínajú aplikovať 670k, 750k transakcií
06:50 — kvôli prerušenému spojeniu blok #85 (50a) nebol validovaný
06:55 — submit uzol #2 vzal z poolu 888145 transakcií a formuje blok #90 (50a)
08:14 — blok #90 (50a) bol podpísaný a poslaný iným uzlom na validáciu
09:04 — blok #90 (50a) bol validovaný a poslaný do koreňového reťazca
11:23 — všetky uzly dostali z koreňového reťazca informácie o tom, že blok #90 (50a) bol pridaný a začínajú aplikovať 888145 transakcií. Medzičasom server #3 už pridal transakcie z blokov #88 (d3b), #89(214)
12:11 — všetky pooly sú prázdne
13:41 — všetky uzly servera #3 obsahujú 3 milióny transakcií a tokenov
14:35 — všetky uzly servera #1 obsahujú 3 milióny transakcií a tokenov
19:24 — všetky uzly servera #2 obsahujú 3 milióny transakcií a tokenov
Prekážky
Počas vývoja Plasma Cash sme narazili na nasledujúce problémy, ktoré postupne riešime:
1. Konflikt interakcie rôznych funkcií systému. Napríklad funkcia pridávania transakcií do poolu blokovala prácu submitu a validácie blokov, a naopak, čo viedlo k poklesu rýchlosti.
2. Nebolo ihneď jasné, akým spôsobom poslať obrovské množstvo transakcií a pritom minimalizovať náklady na prenos dát.
3. Nebolo jasné, akým spôsobom a kde uchovávať dáta, aby sme dosiahli vysoké výsledky.
4. Nebolo jasné, ako zorganizovať sieť medzi uzlami, keďže veľkosť bloku s 1 miliónom transakcií zaberá približne 100 MB.
5. Práca v jednofunkčnom režime prerušiť spojenie medzi uzlami, keď sa vykonávajú dlhé výpočty (napríklad konštrukcia Merkleho stromu a výpočet jeho hash).
Ako sme sa s týmto všetkým vysporiadali?
Prvá verzia uzla Plasma Cash predstavovala akýsi kombinovaný systém, ktorý mohol robiť všetko naraz: prijímať transakcie, odosielať a validovať bloky, a poskytoval API na prístup k dátam. Keďže NodeJS je pôvodne jednoprvkový, ťažká funkcia výpočtu Merkleho stromu zablokovala funkciu pridávania transakcie. Videli sme dve možnosti riešenia tohto problému:
1. Spustiť niekoľko procesov NodeJS, z ktorých každý vykonáva určité funkcie.
2. Použiť worker_threads a preniesť vykonanie časti kódu do vlákien.
Nakoniec sme využili obe možnosti súčasne: logicky sme rozdelili jeden uzol na 3 časti, ktoré môžu pracovať samostatne, ale zároveň sú synchronizované.
1. Uzol pre odosielanie, ktorý prijíma transakcie do poolu a vytvára bloky.
2. Validujúci uzol, ktorý kontroluje platnosť uzlov.
3. API uzol — poskytuje API na prístup k dátam.
Každému uzlu sa dá pripojiť prostredníctvom unix socketu pomocou CLI.
Ťažké operácie, ako je výpočet Merkleho stromu, sme preniesli do samostatného vlákna.
Tak sme dosiahli normálnu funkčnosť všetkých funkcií Plasma Cash súčasne a bez výpadkov.
Hneď ako systém funkčne začal pracovať, začali sme testovať rýchlosť a, žiaľ, získali sme neuspokojivé výsledky: 5 000 transakcií za sekundu a až 50 000 transakcií v bloku. Museli sme zistiť, čo bolo implementované nesprávne.
Začali sme testovať mechanizmus komunikácie s Plasma Cash, aby sme zistili maximálnu výkonnosť systému. Predtým sme písali, že uzol Plasma Cash poskytuje unix socket rozhranie. Pôvodne bolo textové. JSON objekty sa posielali pomocou `JSON.parse()` a `JSON.stringify()`.
{
"action": "sendTransaction",
"payload":{
"prevHash": "0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0",
"prevBlock": 41,
"tokenId": "57570139642005649136210751546585740989890521125187435281313126554130572876445",
"newOwner": "0x200eabe5b26e547446ae5821622892291632d4f4",
"type": "pay",
"data": "",
"signature": "0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c"
}
}
Zmerali sme rýchlosť prenosu takýchto objektov a dostali sme ~ 130k za sekundu. Skúšali sme nahradiť štandardné funkcie na prácu s json, ale výkon sa nezvýšil. Musí byť motor V8 dobre optimalizovaný na tieto operácie.
Práca s transakciami, tokenmi a blokmi sa u nás realizovala prostredníctvom tried. Pri vytváraní týchto tried sa výkon znížil na polovicu, čo naznačuje, že OOP nám nevyhovuje. Museli sme prepisovať všetko na čisto funkčný prístup.
Zápis do databázy
Pôvodne bol vybraný Redis ako jedno z najvýkonnejších riešení, ktoré vyhovuje našim požiadavkám: key-value úložisko, práca s hash-tabulkami, množinami. Spustili sme redis-benchmark a dostali sme ~80 000 operácií za sekundu v režime 1 pipelining.
Pre vysoký výkon sme Redis nastavili ešte precíznejšie:
- Nastavili sme unix socket spojenie.
- Vypnuli sme ukladanie stavu na disk (pre spoľahlivosť je možné nastaviť replikáciu a vykonávať ukladanie na disk v samostatnom Redis).
V Redis je pool — to je hash-tabuka, pretože potrebujeme mať možnosť získavať všetky transakcie jednou požiadavkou a vymazávať transakcie jednotlivo. Skúšali sme použiť obyčajný zoznam, ale ten pri načítaní celého zoznamu funguje pomalšie.
Pri použití štandardnej knižnice NodeJS pre Redis sme dosiahli výkon 18 000 transakcií za sekundu. Rýchlosť sa znížila 9-krát.
Keďže benchmark nám ukázal schopnosti jasne 5-krát väčšie, začali sme optimalizovať. Zmenili sme knižnicu na ioredis a dosiahli sme výkon už 25 000 za sekundu. Transakcie sme pridávali jednotlivo, používajúc príkaz `hset`. Takto sme generovali množstvo požiadaviek do Redis. Napadlo nás spojiť transakcie do dávok a odosielať ich jedným príkazom `hmset`. Výsledok — 32 000 za sekundu.
Z niekoľkých dôvodov, ktoré popíšeme nižšie, pracujeme s údajmi pomocou `Buffer` a, ako sa ukázalo, ak ho prevedieme na text (`buffer.toString('hex')`) pred zapisovaním, môžeme získať dodatočný výkon. Takto sa nám podarilo zvýšiť rýchlosť na 35 000 za sekundu. V súčasnosti sme sa rozhodli prerušiť ďalšiu optimalizáciu.
Museli sme prejsť na binárny protokol, pretože:
1. Systém často vypočítava hash, podpisy a podobne, a na to potrebuje údaje v `Buffer`.
2. Pri prenose medzi službami majú binárne údaje menšiu veľkosť ako text. Napríklad pri odosielaní bloku s 1 miliónom transakcií môžu byť údaje v texte väčšie ako 300 megabajtov.
3. Neustále konvertovanie údajov ovplyvňuje výkon.
Preto sme ako základ vzali náš vlastný binárny protokol na uchovávanie a prenos dát, vyvinutý na báze vynikajúcej knižnice `binary-data`.
V dôsledku toho máme nasledujúce dátové štruktúry:
— Transakcia
```json
{
prevHash: BD.types.buffer(20),
prevBlock: BD.types.uint24le,
tokenId: BD.types.string(null),
type: BD.types.uint8,
newOwner: BD.types.buffer(20),
dataLength: BD.types.uint24le,
data: BD.types.buffer(({current}) => current.dataLength),
signature: BD.types.buffer(65),
hash: BD.types.buffer(32),
blockNumber: BD.types.uint24le,
timestamp: BD.types.uint48le,
}
```
— Token
```json
{
id: BD.types.string(null),
owner: BD.types.buffer(20),
block: BD.types.uint24le,
amount: BD.types.string(null),
}
```
— Blok
```json
{
number: BD.types.uint24le,
merkleRootHash: BD.types.buffer(32),
signature: BD.types.buffer(65),
countTx: BD.types.uint24le,
transactions: BD.types.array(Transaction.Protocol, ({current}) => current.countTx),
timestamp: BD.types.uint48le,
}
```
Bežnými príkazmi `BD.encode(block, Protocol).slice();` a ` BD.decode(buffer, Protocol)` premieňame dáta na `Buffer` na uloženie v Redis alebo na zaslanie inej uzloch a spätné získanie dát.
Máme tiež 2 binárne protokoly na prenos dát medzi službami:
— Protokol na interakciu s Plasma uzlom cez unix socket
```json
{
type: BD.types.uint8,
messageId: BD.types.uint24le,
error: BD.types.uint8,
length: BD.types.uint24le,
payload: BD.types.buffer(({node}) => node.length)
}
```
kde:
- `type` — akcia, ktorú je potrebné vykonať, napríklad 1 — sendTransaction, 2 — getTransaction;
- `payload` — dáta, ktoré je potrebné odoslať do príslušnej funkcie;
- `messageId` — ID správy na identifikáciu odpovede.
— Protokol interakcie medzi uzlami
```json
{
code: BD.types.uint8,
versionProtocol: BD.types.uint24le,
seq: BD.types.uint8,
countChunk: BD.types.uint24le,
chunkNumber: BD.types.uint24le,
length: BD.types.uint24le,
payload: BD.types.buffer(({node}) => node.length)
}
```
kde:
- `code` — kód správy, napríklad 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
- `versionProtocol` — verzia protokolu, pretože v sieti môžu byť uzly s rôznymi verziami a môžu fungovať odlišne;
- `seq` — identifikátor správy;
- `countChunk` a `chunkNumber` sú potrebné na fragmentáciu veľkých správ;
- `length` a `payload` dĺžka a samotné dáta.
Keďže sme dáta vopred typizovali, konečný systém funguje oveľa rýchlejšie ako knižnica `rlp` od Etherea. Bohužiaľ, zatiaľ sa nám nepodarilo od nej upustiť, pretože je potrebné dolaďovať smart kontrakt, čo plánujeme urobiť v budúcnosti.
Ak sa nám podarilo dosiahnuť rýchlosť 35 000 transakcií za sekundu, musíme ich spracovávať v optimálnom čase. Keďže predpokladaný čas na vytvorenie bloku trvá 30 sekúnd, je potrebné zahrnúť do bloku 1 000 000 transakcií, čo znamená prenos viacerých 100 MB dát.
Pôvodne sme používali knižnicu `ethereumjs-devp2p` na komunikáciu medzi uzlami, ale táto si neporadila s takým množstvom dát. Preto sme využili knižnicu `ws` a nastavili prenos binárnych dát cez websocket. Samozrejme, pri prenose veľkých balíkov dát sme sa stretli s problémami, ale rozdelili sme ich na časti a teraz už takéto problémy nemáme.
Taktiež vytváranie Merkleho stromu a výpočet hashu 1 000 000 transakcií trvá približne 10 sekúnd nepretržitého výpočtu. Počas tohto času sa spojenie so všetkými uzlami preruší. Rozhodli sme sa presunúť tento výpočet do samostatného vlákna.
Vývody:
Naša zistenia nie sú nové, ale z nejakého dôvodu na ne mnohí odborníci zabúdajú pri vývoji.
- Použitie funkcionálneho programovania namiesto objektovo orientovaného programovania zvyšuje výkon.
- Monolit je horší než služobná architektúra pre výkonný systém na NodeJS.
- Použitie `worker_threads` na ťažké výpočty zlepšuje odozvu systému, najmä pri práci s operáciami I/O.
- unix socket je stabilnejší a rýchlejší ako http požiadavky.
- Ak je potrebné rýchlo prenášať veľké dáta cez sieť, je lepšie využiť websockety a posielať binárne dáta rozdelené na časti, ktoré môžu byť opätovne zaslané, ak nedôjdu, a potom ich zlúčiť do jednej správy.
Pozývame vás navštíviť GitHub projektu:
Článok bol napísaný v spolupráci s Alexandrom Našivanom, hlavným vývojárom .
Zdroj: habr.com
