Test pubblico: una soluzione per la privacy e la scalabilità su Ethereum

Blokcheyn è una tecnologia innovativa che promette di migliorare molti aspetti della vita umana. Trasferisce processi e prodotti reali nello spazio digitale, garantisce velocità e affidabilità delle transazioni finanziarie, ne riduce i costi e consente inoltre di creare moderne applicazioni DAPP utilizzando contratti intelligenti in reti decentralizzate.

Considerati i numerosi vantaggi e le diverse applicazioni della blockchain, può sembrare sorprendente che questa promettente tecnologia non sia ancora riuscita a farsi strada in tutti i settori. Il problema è che le moderne blockchain decentralizzate mancano di scalabilità. Ethereum elabora circa 20 transazioni al secondo, il che non è sufficiente per soddisfare le esigenze delle aziende dinamiche di oggi. Allo stesso tempo, le aziende che utilizzano la tecnologia blockchain sono riluttanti ad abbandonare Ethereum a causa del suo elevato grado di protezione dagli hacker e dai guasti della rete.

Per garantire decentralizzazione, sicurezza e scalabilità nella blockchain, risolvendo così il trilemma della scalabilità, il team di sviluppo Opporty ha creato Plasma Cash, una catena sussidiaria composta da uno smart contract e una rete privata basata su Node.js, che trasferisce periodicamente il proprio stato alla root chain (Ethereum).

Test pubblico: una soluzione per la privacy e la scalabilità su Ethereum

Processi chiave in Plasma Cash

1. L'utente chiama la funzione del contratto intelligente "deposito", trasferendovi la quantità di ETH che desidera depositare nel token Plasma Cash. La funzione del contratto intelligente crea un token e genera un evento al riguardo.

2. I nodi Plasma Cash iscritti agli eventi del contratto intelligente ricevono un evento sulla creazione di un deposito e aggiungono una transazione sulla creazione di un token al pool.

3. Periodicamente, speciali nodi Plasma Cash prendono tutte le transazioni dal pool (fino a 1 milione) e ne formano un blocco, calcolano l'albero Merkle e, di conseguenza, l'hash. Questo blocco viene inviato ad altri nodi per la verifica. I nodi controllano se l'hash Merkle è valido e se le transazioni sono valide (ad esempio, se il mittente del token è il suo proprietario). Dopo aver verificato il blocco, il nodo chiama la funzione "submitBlock" dello smart contract, che salva il numero del blocco e l'hash Merkle nella catena edge. Il contratto intelligente genera un evento che indica l'avvenuta aggiunta di un blocco. Le transazioni vengono rimosse dal pool.

4. I nodi che ricevono l'evento di invio del blocco iniziano ad applicare le transazioni aggiunte al blocco.

5. Ad un certo punto, il proprietario (o non proprietario) del token vuole ritirarlo da Plasma Cash. Per fare ciò, chiama la funzione `startExit`, passandovi le informazioni sulle ultime 2 transazioni sul token, che confermano che è il proprietario del token. Lo smart contract, utilizzando l'hash Merkle, verifica la presenza di transazioni nei blocchi e invia il token per il ritiro, che avverrà in due settimane.

6. Se l'operazione di ritiro del token è avvenuta con violazioni (il token è stato speso dopo l'inizio della procedura di prelievo oppure il token era già di qualcun altro prima del ritiro), il proprietario del token può opporsi al ritiro entro due settimane.

Test pubblico: una soluzione per la privacy e la scalabilità su Ethereum

La privacy si ottiene in due modi

1. La catena radice non sa nulla delle transazioni generate e inoltrate all'interno della catena figlio. Le informazioni su chi ha depositato e ritirato ETH da Plasma Cash rimangono pubbliche.

2. La catena secondaria consente transazioni anonime utilizzando zk-SNARKs.

Pila tecnologica

  • NodeJS
  • Redis
  • Etherium
  • Soild

Test

Durante lo sviluppo di Plasma Cash, abbiamo testato la velocità del sistema e abbiamo ottenuto i seguenti risultati:

  • vengono aggiunte al pool fino a 35 transazioni al secondo;
  • in un blocco possono essere memorizzate fino a 1 di transazioni.

I test sono stati effettuati sui seguenti 3 server:

1. Intel Core i7-6700 Quad-Core Skylake incl. SSD NVMe: 512 GB, 64 GB di RAM DDR4
Sono stati sollevati 3 nodi di convalida Plasma Cash.

2. AMD Ryzen 7 1700X Octa-Core “Summit Ridge” (Zen), SSD SATA – 500 GB, 64 GB di RAM DDR4
Il nodo ETH del testnet Ropsten è stato creato.
Sono stati sollevati 3 nodi di convalida Plasma Cash.

3. Intel Core i9-9900K Octa-Core incl. SSD NVMe: 1 TB, 64 GB di RAM DDR4
1 nodo di invio di Plasma Cash è stato generato.
Sono stati sollevati 3 nodi di convalida Plasma Cash.
È stato lanciato un test per aggiungere transazioni alla rete Plasma Cash.

Totale: 10 nodi Plasma Cash in una rete privata.

Prova 1

Esiste un limite di 1 milione di transazioni per blocco. Pertanto, 1 milione di transazioni rientrano in 2 blocchi (poiché il sistema riesce a prendere parte delle transazioni e ad inviarle mentre vengono inviate).


Stato iniziale: ultimo blocco n.7; Nel database sono archiviati 1 milione di transazioni e token.

00:00: inizio dello script di generazione della transazione
01:37 - Sono state create 1 milione di transazioni ed è iniziato l'invio al nodo
01:46 — Il nodo di invio ha preso 240 transazioni dal pool e forma il blocco n. 8. Vediamo anche che 320 transazioni vengono aggiunte al pool in 10 secondi
01:58 — il blocco n. 8 viene firmato e inviato per la convalida
02:03 — il blocco n. 8 viene convalidato e la funzione `submitBlock` dello smart contract viene richiamata con l'hash Merkle e il numero del blocco
02:10: lo script demo ha finito di funzionare, inviando 1 milione di transazioni in 32 secondi
02:33 - i nodi hanno iniziato a ricevere informazioni che il blocco n. 8 è stato aggiunto alla catena radice e hanno iniziato a eseguire transazioni da 240
02:40 - 240 transazioni sono state rimosse dal pool, che si trova già nel blocco n. 8
02:56 — il nodo di invio ha preso le restanti 760 transazioni dal pool e ha iniziato a calcolare l'hash Merkle e a firmare il blocco n. 9
03:20 - tutti i nodi contengono 1 milione di transazioni e token da 240
03:35 — il blocco n. 9 viene firmato e inviato per la convalida ad altri nodi
03:41 - si è verificato un errore di rete
04:40: l'attesa per la convalida del blocco n. 9 è scaduta
04:54 — il nodo di invio ha preso le restanti 760 transazioni dal pool e ha iniziato a calcolare l'hash Merkle e a firmare il blocco n. 9
05:32 — il blocco n. 9 viene firmato e inviato per la convalida ad altri nodi
05:53 — il blocco n. 9 viene convalidato e inviato alla catena root
06:17 - i nodi hanno iniziato a ricevere informazioni che il blocco n. 9 è stato aggiunto alla catena radice e hanno iniziato a eseguire transazioni da 760
06:47 — il pool ha cancellato le transazioni che si trovano nel blocco n. 9
09:06 - tutti i nodi contengono 2 milioni di transazioni e token

Prova 2

C'è un limite di 350k per blocco. Di conseguenza, abbiamo 3 blocchi.


Stato iniziale: ultimo blocco n. 9; Nel database sono archiviati 2 milioni di transazioni e token

00:00: lo script di generazione della transazione è già stato avviato
00:44 - Sono state create 1 milione di transazioni ed è iniziato l'invio al nodo
00:56 — Il nodo di invio ha preso 320 transazioni dal pool e forma il blocco n. 10. Vediamo anche che 320 transazioni vengono aggiunte al pool in 10 secondi
01:12 — il blocco n. 10 viene firmato e inviato ad altri nodi per la convalida
01:18: lo script demo ha finito di funzionare, inviando 1 milione di transazioni in 34 secondi
01:20 — il blocco n. 10 viene convalidato e inviato alla catena root
01:51 - tutti i nodi hanno ricevuto informazioni dalla catena root che è stato aggiunto il blocco n. 10 e iniziano ad applicare transazioni da 320
02:01 - Il pool è stato autorizzato per 320 transazioni aggiunte al blocco n. 10
02:15 — il nodo di invio ha preso 350 transazioni dal pool e forma il blocco n. 11
02:34 — il blocco n. 11 viene firmato e inviato ad altri nodi per la convalida
02:51 — il blocco n. 11 viene convalidato e inviato alla catena root
02:55 — l'ultimo nodo ha completato le transazioni dal blocco n. 10
10:59 — la transazione con l'invio del blocco n. 9 ha richiesto molto tempo nella catena root, ma è stata completata e tutti i nodi hanno ricevuto informazioni al riguardo e hanno iniziato a eseguire 350 transazioni
11:05 - Il pool è stato autorizzato per 320 transazioni aggiunte al blocco n. 11
12:10 - tutti i nodi contengono 1 milione di transazioni e token da 670
12:17: il nodo di invio ha preso 330 transazioni dal pool e forma il blocco n. 12
12:32 — il blocco n. 12 viene firmato e inviato ad altri nodi per la convalida
12:39 — il blocco n. 12 viene convalidato e inviato alla catena root
13:44 - tutti i nodi hanno ricevuto informazioni dalla catena root che è stato aggiunto il blocco n. 12 e iniziano ad applicare transazioni da 330
14:50 - tutti i nodi contengono 2 milioni di transazioni e token

Prova 3

Nel primo e nel secondo server, un nodo di convalida è stato sostituito da un nodo di invio.


Stato iniziale: ultimo blocco #84; 0 transazioni e token salvati nel database

00:00 — Sono stati lanciati 3 script che generano e inviano 1 milione di transazioni ciascuno
01:38 — Sono state create 1 milione di transazioni ed è iniziato l'invio al nodo n. 3
01:50 — il nodo di invio n. 3 ha preso 330 transazioni dal pool e forma il blocco n. 85 (f21). Vediamo anche che 350 transazioni vengono aggiunte al pool in 10 secondi
01:53 — Sono state create 1 milione di transazioni ed è iniziato l'invio al nodo n. 1
01:50 — il nodo di invio n. 3 ha preso 330 transazioni dal pool e forma il blocco n. 85 (f21). Vediamo anche che 350 transazioni vengono aggiunte al pool in 10 secondi
02:01 — il nodo di invio n. 1 ha preso 250 transazioni dal pool e forma il blocco n. 85 (65e)
02:06 — il blocco n. 85 (f21) viene firmato e inviato ad altri nodi per la convalida
02:08 — Lo script demo del server n. 3, che ha inviato 1 milione di transazioni in 30 secondi, ha finito di funzionare
02:14 — il blocco #85 (f21) viene convalidato e inviato alla catena root
02:19 — il blocco n. 85 (65e) viene firmato e inviato ad altri nodi per la convalida
02:22 — Sono state create 1 milione di transazioni ed è iniziato l'invio al nodo n. 2
02:27 — blocco n. 85 (65e) convalidato e inviato alla catena radice
02:29 — il nodo di invio n. 2 ha preso 111855 transazioni dal pool e forma il blocco n. 85 (256).
02:36 — il blocco n. 85 (256) viene firmato e inviato ad altri nodi per la convalida
02:36 — Lo script demo del server n. 1, che ha inviato 1 milione di transazioni in 42.5 secondi, ha finito di funzionare
02:38 — il blocco n. 85 (256) viene convalidato e inviato alla catena radice
03:08 — Lo script del server n. 2 ha terminato di funzionare, inviando 1 milione di transazioni in 47 secondi
03:38 - tutti i nodi hanno ricevuto informazioni dalla catena root che i blocchi #85 (f21), #86(65e), #87(256) sono stati aggiunti e hanno iniziato ad applicare transazioni 330k, 250k, 111855
03:49 - il pool è stato cancellato a 330k, 250k, 111855 transazioni che sono state aggiunte ai blocchi #85 (f21), #86(65e), #87(256)
03:59 — il nodo di invio n. 1 ha preso 888145 transazioni dal pool e forma il blocco n. 88 (214), il nodo di invio n. 2 ha preso 750 transazioni dal pool e forma il blocco n. 88 (50a), il nodo di invio n. 3 ha preso 670 transazioni da la piscina e forma il blocco n.88 (d3b)
04:44 — il blocco n. 88 (d3b) viene firmato e inviato ad altri nodi per la convalida
04:58 — il blocco n. 88 (214) viene firmato e inviato ad altri nodi per la convalida
05:11 — il blocco n. 88 (50a) viene firmato e inviato ad altri nodi per la convalida
05:11 — il blocco #85 (d3b) viene convalidato e inviato alla catena root
05:36 — il blocco n. 85 (214) viene convalidato e inviato alla catena radice
05:43 - tutti i nodi hanno ricevuto informazioni dalla catena root che i blocchi #88 (d3b), #89(214) sono stati aggiunti e stanno iniziando ad applicare transazioni da 670k, 750k
06:50 — a causa di un errore di comunicazione, il blocco n. 85 (50a) non è stato convalidato
06:55 — il nodo di invio n. 2 ha preso 888145 transazioni dal pool e forma il blocco n. 90 (50a)
08:14 — il blocco n. 90 (50a) viene firmato e inviato ad altri nodi per la convalida
09:04 — il blocco n. 90 (50a) viene convalidato e inviato alla catena radice
11:23 - tutti i nodi hanno ricevuto informazioni dalla catena root che è stato aggiunto il blocco n. 90 (50a) e iniziano ad applicare 888145 transazioni. Allo stesso tempo, il server #3 ha già applicato le transazioni dai blocchi #88 (d3b), #89(214)
12:11 - tutte le piscine sono vuote
13:41 — tutti i nodi del server n. 3 contengono 3 milioni di transazioni e token
14:35 — tutti i nodi del server n. 1 contengono 3 milioni di transazioni e token
19:24 — tutti i nodi del server n. 2 contengono 3 milioni di transazioni e token

ostacoli

Durante lo sviluppo di Plasma Cash, abbiamo riscontrato i seguenti problemi, che abbiamo gradualmente risolto e stiamo risolvendo:

1. Conflitto nell'interazione di varie funzioni del sistema. Ad esempio, la funzione di aggiunta di transazioni al pool ha bloccato il lavoro di invio e convalida dei blocchi e viceversa, il che ha portato a un calo di velocità.

2. Non è stato immediatamente chiaro come inviare un numero enorme di transazioni riducendo al minimo i costi di trasferimento dei dati.

3. Non era chiaro come e dove archiviare i dati per ottenere risultati elevati.

4. Non era chiaro come organizzare la rete tra i nodi, poiché la dimensione di un blocco con 1 milione di transazioni occupa circa 100 MB.

5. Lavorare in modalità a thread singolo interrompe la connessione tra i nodi quando si verificano calcoli lunghi (ad esempio, costruendo un albero Merkle e calcolando il suo hash).

Come abbiamo affrontato tutto questo?

La prima versione del nodo Plasma Cash era una sorta di combinazione in grado di fare tutto allo stesso tempo: accettare transazioni, inviare e convalidare blocchi e fornire un'API per l'accesso ai dati. Poiché NodeJS è nativamente a thread singolo, la pesante funzione di calcolo dell'albero Merkle ha bloccato la funzione di aggiunta transazione. Abbiamo visto due opzioni per risolvere questo problema:

1. Avvia diversi processi NodeJS, ognuno dei quali svolge funzioni specifiche.

2. Utilizza worker_threads e sposta l'esecuzione di parte del codice nei thread.

Di conseguenza, abbiamo utilizzato entrambe le opzioni contemporaneamente: abbiamo diviso logicamente un nodo in 3 parti che possono funzionare separatamente, ma allo stesso tempo in modo sincrono

1. Nodo di invio, che accetta transazioni nel pool e crea blocchi.

2. Un nodo di convalida che controlla la validità dei nodi.

3. Nodo API: fornisce un'API per l'accesso ai dati.

In questo caso, puoi connetterti a ciascun nodo tramite un socket Unix utilizzando cli.

Abbiamo spostato le operazioni pesanti, come il calcolo dell'albero Merkle, in un thread separato.

Pertanto, abbiamo raggiunto il normale funzionamento di tutte le funzioni Plasma Cash contemporaneamente e senza guasti.

Una volta che il sistema è entrato in funzione, abbiamo iniziato a testarne la velocità e, purtroppo, abbiamo ottenuto risultati insoddisfacenti: 5 transazioni al secondo e fino a 000 transazioni per blocco. Ho dovuto capire cosa è stato implementato in modo errato.

Per cominciare, abbiamo iniziato a testare il meccanismo di comunicazione con Plasma Cash per scoprire la massima capacità del sistema. Abbiamo scritto in precedenza che il nodo Plasma Cash fornisce un'interfaccia socket Unix. Inizialmente era basato sul testo. gli oggetti json sono stati inviati utilizzando `JSON.parse()` e `JSON.stringify()`.

```json
{
  "action": "sendTransaction",
  "payload":{
    "prevHash": "0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0",
    "prevBlock": 41,
    "tokenId": "57570139642005649136210751546585740989890521125187435281313126554130572876445",
    "newOwner": "0x200eabe5b26e547446ae5821622892291632d4f4",
    "type": "pay",
    "data": "",
    "signature": "0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c"
  }
}
```

Abbiamo misurato la velocità di trasferimento di tali oggetti e abbiamo riscontrato ~ 130k al secondo. Abbiamo provato a sostituire le funzioni standard per lavorare con JSON, ma le prestazioni non sono migliorate. Il motore V8 deve essere ben ottimizzato per queste operazioni.

Abbiamo lavorato con transazioni, token e blocchi attraverso le classi. Durante la creazione di tali classi, le prestazioni sono diminuite di 2 volte, il che indica che l'OOP non è adatto a noi. Ho dovuto riscrivere tutto secondo un approccio puramente funzionale.

Registrazione nel database

Inizialmente, Redis è stata scelta per l'archiviazione dei dati come una delle soluzioni più produttive che soddisfa le nostre esigenze: archiviazione di valori-chiave, lavoro con tabelle hash, set. Abbiamo lanciato Redis-Benchmark e abbiamo ottenuto circa 80 operazioni al secondo in 1 modalità pipeline.

Per ottenere prestazioni elevate, abbiamo ottimizzato Redis in modo più accurato:

  • È stata stabilita una connessione socket Unix.
  • Abbiamo disabilitato il salvataggio dello stato su disco (per affidabilità, puoi configurare una replica e salvare su disco in un Redis separato).

In Redis, un pool è una tabella hash perché dobbiamo essere in grado di recuperare tutte le transazioni in una query ed eliminare le transazioni una per una. Abbiamo provato a utilizzare un elenco normale, ma è più lento durante lo scaricamento dell'intero elenco.

Quando si utilizza NodeJS standard, le librerie Redis hanno raggiunto una prestazione di 18k transazioni al secondo. La velocità è diminuita 9 volte.

Poiché il benchmark ci ha mostrato che le possibilità erano chiaramente 5 volte maggiori, abbiamo iniziato a ottimizzare. Abbiamo cambiato la libreria in ioredis e abbiamo ottenuto prestazioni di 25k al secondo. Abbiamo aggiunto le transazioni una per una utilizzando il comando `hset`. Quindi stavamo generando molte query in Redis. È nata l'idea di combinare le transazioni in batch e inviarle con un comando `hmset`. Il risultato è 32k al secondo.

Per diversi motivi, che descriveremo di seguito, lavoriamo con i dati utilizzando `Buffer` e, a quanto pare, se lo converti in testo (`buffer.toString('hex')`) prima della scrittura, puoi ottenere ulteriori prestazione. Pertanto, la velocità è stata aumentata a 35k al secondo. Al momento, abbiamo deciso di sospendere ulteriori ottimizzazioni.

Abbiamo dovuto passare ad un protocollo binario perché:

1. Il sistema spesso calcola hash, firme, ecc. e per questo ha bisogno di dati nel `Buffer.

2. Quando vengono inviati tra servizi, i dati binari pesano meno del testo. Ad esempio, quando si invia un blocco con 1 milione di transazioni, i dati nel testo possono occupare più di 300 megabyte.

3. La continua trasformazione dei dati influisce sulle prestazioni.

Pertanto, abbiamo preso come base il nostro protocollo binario per la memorizzazione e la trasmissione dei dati, sviluppato sulla base della meravigliosa libreria "binary-data".

Di conseguenza, abbiamo ottenuto le seguenti strutture dati:

-Transazione

  ```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,
  }
  ```

- Gettone

  ```json
  {
    id: BD.types.string(null),
    owner: BD.types.buffer(20),
    block: BD.types.uint24le,
    amount: BD.types.string(null),
  }
  ```

-Bloccare

  ```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,
  }
  ```

Con i soliti comandi `BD.encode(block, Protocol).slice();` e `BD.decode(buffer, Protocol)` convertiamo i dati in `Buffer` per il salvataggio in Redis o l'inoltro a un altro nodo e il recupero del file dati indietro.

Abbiamo anche 2 protocolli binari per il trasferimento dei dati tra servizi:

— Protocollo per l'interazione con Plasma Node tramite socket unix

  ```json
  {
    type: BD.types.uint8,
    messageId: BD.types.uint24le,
    error: BD.types.uint8,
    length: BD.types.uint24le,
    payload: BD.types.buffer(({node}) => node.length)
  }
  ```

dove:

  • `Type` — l'azione da eseguire, ad esempio, 1 — sendTransaction, 2 — getTransaction;
  • "carico utile". — dati che devono essere trasmessi alla funzione appropriata;
  • "ID messaggio". — ID del messaggio in modo che la risposta possa essere identificata.

— Protocollo per l'interazione tra i nodi

  ```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)
  }
  ```

dove:

  • `codice` — codice del messaggio, ad esempio 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
  • "protocollo versione". — versione del protocollo, poiché sulla rete possono sorgere nodi con versioni diverse e funzionare diversamente;
  • "seq". — identificatore del messaggio;
  • "countChunk". и "Numero pezzo". necessario per dividere messaggi di grandi dimensioni;
  • "lunghezza". и "carico utile". lunghezza e i dati stessi.

Dato che abbiamo pre-digitato i dati, il sistema finale è molto più veloce della libreria `rlp` di Ethereum. Purtroppo non abbiamo ancora potuto rifiutarlo, poiché è necessario finalizzare il contratto intelligente, cosa che prevediamo di fare in futuro.

Se riuscissimo a raggiungere la velocità 35/000 transazioni al secondo, dobbiamo anche elaborarle nel tempo ottimale. Poiché il tempo approssimativo di formazione del blocco richiede 30 secondi, dobbiamo includerlo nel blocco 1 000 000 transazioni, il che significa inviarne di più 100 MB di dati.

Inizialmente, abbiamo utilizzato la libreria `ethereumjs-devp2p` per comunicare tra i nodi, ma non poteva gestire così tanti dati. Di conseguenza, abbiamo utilizzato la libreria `ws` e configurato l'invio di dati binari tramite websocket. Naturalmente abbiamo riscontrato problemi anche durante l'invio di pacchetti di dati di grandi dimensioni, ma li abbiamo divisi in blocchi e ora questi problemi sono scomparsi.

Formando anche un albero Merkle e calcolando l'hash 1 000 000 le transazioni richiedono circa 10 secondi di calcolo continuo. Durante questo periodo, la connessione con tutti i nodi riesce a interrompersi. Si è deciso di spostare questo calcolo in un thread separato.

Conclusioni:

In realtà, le nostre scoperte non sono nuove, ma per qualche motivo molti esperti se ne dimenticano durante lo sviluppo.

  • L'uso della programmazione funzionale invece della programmazione orientata agli oggetti migliora la produttività.
  • Il monolite è peggio di un’architettura di servizi per un sistema NodeJS produttivo.
  • L'utilizzo di "worker_threads" per calcoli pesanti migliora la reattività del sistema, soprattutto quando si ha a che fare con operazioni di i/o.
  • Il socket Unix è più stabile e più veloce delle richieste http.
  • Se è necessario trasferire rapidamente grandi quantità di dati sulla rete, è meglio utilizzare i websocket e inviare dati binari, divisi in blocchi, che possono essere inoltrati se non arrivano e quindi combinati in un unico messaggio.

Ti invitiamo a visitare GitHub pROGETTO: https://github.com/opporty-com/Plasma-Cash/tree/new-version

L'articolo è stato co-scritto da Alessandro Nashivan, sviluppatore anziano Soluzione intelligente Inc.

Fonte: habr.com

Aggiungi un commento