Conosciamo Node.js per le sue prestazioni fulminee. Eppure, come con qualsiasi linguaggio, è possibile scrivere codice Node.js che funziona peggio di quanto si vorrebbe per i propri utenti. Per combattere questo, abbiamo bisogno di un adeguato test delle prestazioni. Oggi, ci occuperemo proprio di questo con uno sguardo approfondito su come impostare ed eseguire un test delle prestazioni e analizzare i risultati in modo da poter creare applicazioni Node.js veloci come la luce.

Il modo migliore per capire come testare le prestazioni della tua applicazione è quello di camminare attraverso un esempio.

Puoi usare Node.js per molti scopi: scrivere script per eseguire attività, eseguire un server web, o servire file statici, come un sito web. Oggi, cammineremo attraverso i passi per testare un’API web HTTP di Node.js. Ma se stai costruendo qualcos’altro in Node, non preoccuparti, molti dei principi saranno simili.

La natura unica delle prestazioni di Node.js

Prima di iniziare, diamo una rapida occhiata ad una delle caratteristiche più uniche delle prestazioni di Node.js. Avremo bisogno di conoscere queste caratteristiche in seguito, quando eseguiremo i nostri test di performance.

Di cosa sto parlando?

La grande considerazione per le applicazioni Node.js è il loro comportamento single-threaded, run-to-completion, facilitato da quello che è conosciuto come event loop. Ora, so cosa state pensando: è molto. Quindi scomponiamo un po’ le cose in modo da capire cosa significano.

Iniziamo con il threading singolo. Il threading, come concetto, permette l’elaborazione concorrente all’interno di un’applicazione. Node.js non ha questa capacità, almeno non nel senso tradizionale. Invece, per scrivere applicazioni che eseguono più compiti contemporaneamente, abbiamo il codice asincrono e l’event loop.

L’event loop

Cos’è l’event loop?

L’event loop è il modo di Node.js di spezzare processi di lunga durata in piccoli pezzi. Funziona come un battito cardiaco: Ogni pochi millisecondi, Node.js controlla una coda di lavoro per avviare nuovi compiti. Se c’è lavoro, li porterà sullo stack delle chiamate e poi li eseguirà fino al completamento (parleremo presto del run-to-completion).

Facendo ripartire i compiti, Node.js può fare il multi-task, che è il vostro sostituto del threading. Ciò significa che mentre un compito è in attesa, un altro può iniziare. Quindi, piuttosto che il threading, usiamo codice asincrono, facilitato da stili di programmazione come callback, promesse e async/await. La maggior parte delle API di Node out-of-the-box hanno sia un metodo di esecuzione sincrono che asincrono.

Ok, quindi forse vi state chiedendo: cosa ha a che fare tutto questo tecno-jargon con le prestazioni?

Lascia che ti spieghi…

Le prestazioni di Node.js e il ciclo degli eventi

Immagina di costruire un’applicazione Node.js con due endpoint: uno per il caricamento dei file e uno che recupera un profilo utente. L’API del profilo utente sarà probabilmente richiesta molto più spesso del caricamento dei file, e se non risponde abbastanza velocemente, bloccherà ogni caricamento di pagina per ogni utente – non va bene.

L’API di caricamento utente è usata poco frequentemente. Inoltre, gli utenti si aspettano che il caricamento dei compiti richieda tempo, ma sono molto meno indulgenti con i tempi di caricamento delle pagine. Se non programmiamo con il ciclo di eventi in mente, mentre il file viene caricato, Node.js potrebbe finire per monopolizzare tutte le risorse del sistema e potrebbe bloccare gli altri utenti nell’utilizzo della vostra applicazione-uh-oh!

E questo è il motivo per cui è necessario comprendere la natura single-threaded di Node.js. Mentre cambiamo la nostra applicazione, dobbiamo considerare questo comportamento. Vogliamo evitare di fare compiti di lunga durata in modo sincrono, come fare richieste di rete, scrivere file o eseguire un calcolo pesante.

Ora che conosciamo la natura single-threaded di Node.js, possiamo usarla a nostro vantaggio. Andiamo passo dopo passo a vedere come puoi impostare, eseguire e analizzare un test delle prestazioni della tua applicazione Node.js per assicurarti che stai facendo del tuo meglio per sfruttare le capacità prestazionali di Node.js.

Passo 1: Scegliere gli strumenti per il test delle prestazioni di Node.js

Prima di tutto, dovrai scegliere uno strumento che ti permetta di eseguire i test delle prestazioni. Ci sono molti strumenti là fuori, tutti con diversi pro e contro per l’ottimizzazione delle prestazioni di Node.js. Una cosa principale da considerare è che anche se stai testando un’applicazione Node.js, se stai andando a testare le prestazioni dal mondo esterno attraverso una rete, non importa se il tuo strumento di test delle prestazioni è scritto in Node.js.

Per il test delle prestazioni HTTP di base, mi piace Artillery un semplice strumento di test delle prestazioni scritto in Node.js. È anche particolarmente buono per eseguire test di prestazioni per le richieste API. Artillery funziona scrivendo un file di configurazione che definisce il vostro profilo di carico. Si dice ad Artillery quali endpoint si vogliono richiedere, a quale velocità, per quale durata, ecc.

Uno script di test di base assomiglia a questo:

config: target: 'https://artillery.io' phases: - duration: 60 arrivalRate: 20 defaults: headers: x-my-service-auth: '987401838271002188298567'scenarios:- flow:- get:url: "/docs"

Qui, si sta richiedendo il sito web di Artillery per una durata di 60 secondi con 20 nuovi utenti che arrivano all’URL.

Poi, per eseguire il test, si esegue semplicemente:

artillery run your_config.yml

Artillery farà tutte le richieste alla vostra applicazione che gli avete ordinato. Questo è utile per costruire profili di test delle prestazioni che imitano l’ambiente di produzione. Cosa intendo per profilo di test delle prestazioni? Copriamolo ora.

Passo 2: Creare un profilo di test delle prestazioni di Node.js

Un profilo di test delle prestazioni, come sopra, è una definizione di come il tuo test delle prestazioni verrà eseguito. Vorrai imitare il comportamento del tuo traffico di produzione, o come ci si aspetta che si comporti, se possibile, per fare un accurato tuning delle prestazioni di Node.js. Per esempio, se stai costruendo un sito web di eventi, ti aspetteresti un sacco di traffico nel momento in cui rilasci i biglietti, quindi vorresti costruire un profilo che imiti questo comportamento. Vorreste testare la capacità della vostra applicazione di scalare con grandi quantità di carico in un breve lasso di tempo. In alternativa, se state gestendo un sito di e-commerce, potreste aspettarvi un traffico uniforme. In questo caso, i tuoi profili di test delle prestazioni dovrebbero riflettere questo comportamento.

Sfruttare più profili di test

Un punto divertente e interessante da notare è che puoi creare diversi profili di test ed eseguirli in modo sovrapposto. Per esempio, potreste creare un profilo che imita il vostro livello base di traffico – per esempio, 100 richieste al minuto – e poi imitare ciò che potrebbe accadere se vedeste molto traffico verso il vostro sito, per esempio se metteste delle pubblicità sui motori di ricerca. Testare scenari multipli è importante per un accurato tuning delle prestazioni di Node.js.

Replicare sistemi distribuiti su larga scala

Devo prendermi un secondo per notare qualcosa: quando un’applicazione raggiunge una certa dimensione, imitare il carico in questo modo perde fattibilità. I volumi di traffico che potreste avere potrebbero essere così selvaggi, imprevedibili o di grande volume che è difficile creare un modo realistico di testare la vostra applicazione prima del rilascio.

Ma se questo fosse il caso? Cosa facciamo? Testiamo in produzione.

Potreste pensare, “Woah, aspetta! Non dovremmo testare prima del rilascio?”

È possibile, ma quando un sistema raggiunge una certa dimensione, potrebbe avere senso sfruttare diverse strategie di test delle prestazioni. Puoi sfruttare concetti come il rilascio canarino per mettere i tuoi cambiamenti in produzione e testarli solo con una certa percentuale di utenti. Se vedete una diminuzione delle prestazioni, potete riportare il traffico all’implementazione precedente. Questo processo incoraggia davvero la sperimentazione, e la parte migliore è che stai testando la tua applicazione di produzione reale, quindi nessuna preoccupazione per i risultati dei test che non imitano la produzione.

Finora abbiamo deciso i nostri strumenti, e abbiamo creato profili che ricreano la nostra produzione, come il traffico e i carichi di lavoro. Cosa facciamo adesso? Dobbiamo assicurarci di avere i dati di cui abbiamo bisogno per analizzare la nostra applicazione, e lo facciamo attraverso il monitoraggio delle prestazioni di Node.js e gli strumenti di Application Performance Management (APM). Cos’è un APM? Continua a leggere e te lo farò sapere!

Passo 3: Impostare l’osservabilità/monitoraggio

Non vogliamo semplicemente eseguire il nostro test delle prestazioni contro la nostra applicazione e sperare e pregare. Se lo facciamo, non saremo in grado di capire come si sta comportando e se sta facendo quello che pensiamo debba fare. Quindi, prima di iniziare, dovremmo porci domande come “Per la mia applicazione, cosa significa buono? Quali sono i miei SLA e KPI? Quali metriche sono necessarie per risolvere efficacemente un problema di prestazioni?”

Se la vostra applicazione funziona lentamente, o diversamente da quanto vi aspettavate, avrete bisogno di dati per capire perché in modo da poterla migliorare. Tutte le applicazioni di produzione degne di nota utilizzano una qualche forma di osservabilità e/o soluzione di monitoraggio. Questi strumenti, spesso chiamati APM, ti permettono di visualizzare le metriche critiche delle prestazioni di Node.js sulla tua applicazione in esecuzione.

Per essere operativi con un APM

Gli APM sono di diverse forme e dimensioni, tutti con diverse caratteristiche, prezzi, implicazioni di sicurezza, prestazioni, e così via. Vale la pena di guardarsi un po’ intorno per trovare lo strumento migliore per le proprie esigenze. Sono questi strumenti che ci daranno le intuizioni e i dati di cui abbiamo bisogno quando eseguiamo i nostri test delle prestazioni di Node.js.

Quindi, se sappiamo che dovremmo monitorare la nostra applicazione, che cosa dovremmo monitorare esattamente?

Vogliamo tutti i dati possibili, ma per quanto amiamo i dati, dobbiamo essere realistici su dove iniziare! Il posto migliore per iniziare è con le seguenti tre aree:

  • Log aggregati-I log delle applicazioni vengono emessi implicitamente da alcune librerie o esplicitamente da uno sviluppatore per avere una visione di un’applicazione. La maggior parte degli strumenti di log aggregati permettono di cercare e visualizzare facilmente i dati registrati. Nel nostro caso, potremmo registrare le prestazioni di ciascuna delle nostre API e tracciarle su un grafico.
  • Approfondimenti sull’infrastruttura-La vostra applicazione verrà eseguita su un host di vario tipo, quindi probabilmente vorrete vedere tutti i dati. Se si esegue nel cloud, la maggior parte dei provider fornisce questi dati (anche se in una forma grezza) fuori dalla scatola. I dati che otterrete da questi strumenti copriranno cose come l’utilizzo della CPU e della memoria del vostro host, i dati di connessione, ecc.
  • Monitoraggio dell’applicazione: questo tipo di strumento di solito si trova all’interno del codice dell’applicazione e può trarre spunti su come le funzioni vengono eseguite/chiamate, quali errori vengono lanciati, ecc.

Alcuni strumenti APM, come Retrace, hanno tutte o quasi tutte queste tre caratteristiche riunite in una, mentre altri possono essere più specializzati. A seconda delle tue esigenze, potresti volere uno strumento che faccia tutto o un’intera gamma di strumenti per scopi diversi.

Strumenti su misura per Node.js

In cima agli strumenti, possiamo anche includere altri strumenti e profilatori specifici per Node.js, come i grafici di fiamma, che guardano l’esecuzione delle nostre funzioni o estraggono dati sull’esecuzione dei nostri cicli di eventi. Man mano che diventi più esperto nei test delle prestazioni di Node.js, le tue richieste di dati non potranno che crescere. Vorrai continuare a fare acquisti, sperimentare e aggiornare i tuoi strumenti per capire veramente la tua applicazione.

Ora che abbiamo impostato i nostri strumenti, ottenuto profili realistici per le nostre prestazioni e capito le prestazioni della nostra applicazione, siamo quasi pronti per eseguire i nostri test. Ma prima di farlo, c’è un altro passo: creare l’infrastruttura di test.

Passo 4: Creare l’infrastruttura di test delle prestazioni di Node.js

Si possono eseguire i test delle prestazioni dalla propria macchina se lo si desidera, ma ci sono problemi nel farlo. Finora, abbiamo provato molto duramente con i nostri profili di test, per esempio, per assicurarci che i nostri test sulle prestazioni siano replicati. Un altro fattore nel replicare i nostri test è quello di assicurarci di eseguirli sempre sulla stessa infrastruttura (leggi: macchina).

Uno dei modi più semplici per ottenere un’infrastruttura di test coerente è quello di sfruttare il cloud hosting. Scegliete un host/macchina da cui volete lanciare i vostri test e assicuratevi che ogni volta che eseguite i vostri test sia sempre dalla stessa macchina e preferibilmente anche dalla stessa posizione, per evitare di alterare i vostri dati in base alla latenza della richiesta.

È una buona idea fare uno script di questa infrastruttura, in modo da poterla creare e smontare come e quando necessario. Chiamano questa idea “infrastruttura come codice”. La maggior parte dei provider di cloud lo supportano nativamente, oppure potete usare uno strumento come Terraform per aiutarvi.

Uff! Abbiamo coperto un sacco di terreno finora, e siamo al passo finale: eseguire i nostri test.

Passo 5: eseguire i tuoi test!

L’ultimo passo è quello di eseguire effettivamente i nostri test. Se avviamo la nostra configurazione della linea di comando (come abbiamo fatto nel passo 1), vedremo le richieste alla nostra applicazione Node.js. Con la nostra soluzione di monitoraggio, possiamo controllare come sta andando il nostro ciclo di eventi, se alcune richieste stanno impiegando più tempo di altre, se le connessioni stanno andando fuori tempo, ecc.

La ciliegina sulla torta per i tuoi test di performance è considerare di metterli nella tua pipeline di compilazione e test. Un modo per farlo è quello di eseguire i test di performance durante la notte in modo da poterli rivedere ogni mattina. Artillery fornisce un modo semplice e piacevole per creare questi rapporti, che possono aiutarti a individuare qualsiasi regressione delle prestazioni di Node.js.

Ora hai un Node.js veloce come un fulmine

Questo è un involucro.

Oggi abbiamo parlato dell’importanza dell’event loop per le prestazioni della tua applicazione JavaScript, di come scegliere gli strumenti di test delle prestazioni, di come impostare profili di test delle prestazioni coerenti con Artillery, di quale monitoraggio vorrai impostare per diagnosticare i problemi di prestazioni di Node.js e, infine, come e quando eseguire i test delle prestazioni per ottenere il massimo valore per te e il tuo team.

Sperimenta gli strumenti di monitoraggio, come Retrace APM per Node.js, fai piccole modifiche in modo da poter testare l’impatto dei cambiamenti e rivedi spesso i tuoi rapporti di test in modo da poter individuare le regressioni. Ora hai tutto quello che ti serve per sfruttare le capacità prestazionali di Node.js e scrivere un’applicazione super performante che i tuoi utenti ameranno!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.