Il testing di carico come servizio CI per gli sviluppatori

Il testing di carico come servizio CI per gli sviluppatori

Uno dei problemi che affrontano frequentemente i fornitori di software multiprodotto è la duplicazione delle competenze degli ingegneri — sviluppatori, tester e amministratori infrastruttura — in quasi ogni team. Questo vale anche per gli ingegneri costosi, esperti nel campo del testing di carico.

Invece di concentrarsi sui propri compiti diretti e utilizzare la propria esperienza unica per costruire il processo di testing di carico, scegliere la metodologia, i valori ottimali delle metriche e scrivere test automatici in base ai profili di carico, gli ingegneri si trovano spesso costretti a creare da zero l'infrastruttura di testing, configurare gli strumenti di carico, integrarli nei sistemi CI, impostare il monitoraggio e pubblicare report.

Alcune soluzioni ad alcune problematiche organizzative nel testing, che applichiamo in Positive Technologies, possono essere trovate in un altro articolo. In questo articolo parlerò dell'integrazione dei test di carico all'interno di un pipeline CI utilizzando il concetto di "load testing as a service". Scoprirete come e quali immagini Docker dei generatori di carico possono essere utilizzate nel pipeline CI; come connettere i generatori di carico al proprio progetto CI tramite un modello di build; come appare un demo pipeline per l'esecuzione dei test di carico e la pubblicazione dei risultati. Questo articolo può essere utile per ingegneri di testing software e ingegneri di automazione CI che stanno pensando all'architettura del proprio sistema di carico.

L'essenza del concetto

Il concetto di load testing as a service implica la possibilità di integrare gli strumenti di carico Apache JMeter, Yandex.Tank e framework personalizzati in qualsiasi sistema di continuous integration. L'esempio demo sarà per GitLab CI, ma i principi esposti sono generali per tutti i sistemi CI.

Il load testing come servizio è un servizio centralizzato per effettuare test di carico. I test di carico vengono eseguiti in pool dedicati di agenti, con pubblicazione automatica dei risultati su GitLab Pages, Influx DB e Grafana o su sistemi di reporting dei test (TestRail, ReportPortal, ecc.). L'automazione e la scalabilità sono facilmente implementabili aggiungendo e parametrizzando un comune modello gitlab-ci.yml nel progetto GitLab CI.

Il vantaggio di questo approccio risiede nel fatto che l'intera infrastruttura CI, gli agenti di carico, le immagini Docker delle sorgenti di carico, i pipeline di test e la pubblicazione dei rapporti sono gestiti dal dipartimento centralizzato di automazione (ingegneri DevOps), permettendo agli ingegneri di test di carico di concentrare i loro sforzi sulla creazione dei test e sull'analisi dei risultati, senza doversi occupare di questioni infrastrutturali.

Per semplicità, consideriamo che l'applicazione o il server da testare siano già distribuiti e configurati in anticipo (per questo possono essere utilizzati script automatizzati in Python, SaltStack, Ansible, ecc.). Pertanto, l'intera concezione del testing delle prestazioni come servizio si articola in tre fasi: preparazione, test, pubblicazione dei report. Maggiori dettagli nella scheda (tutte le immagini sono cliccabili):

Il testing di carico come servizio CI per gli sviluppatori

Concetti e definizioni fondamentali nel testing delle prestazioni

Durante l'esecuzione dei test di carico, ci sforziamo di seguire gli standard e la metodologia ISTQB, utilizzando la terminologia appropriata e le metriche raccomandate. Ecco un breve elenco dei principali concetti e definizioni nel testing delle prestazioni.

Agente di carico (load agent) — una macchina virtuale su cui verrà eseguita l'applicazione — sorgente del carico (Apache JMeter, Yandex.Tank o un modulo di carico personalizzato).

Obiettivo del test (target) — server o applicazione installata sul server che sarà sottoposta a carico.

Scenario di test (test case) — un insieme di azioni parametrizzate: azioni degli utenti e reazioni attese a tali azioni, con richieste e risposte di rete registrate, a seconda dei parametri specificati.

Profilo o piano di carico (profile) — in metodologia ISTQB (p. 4.2.4, p. 43) i profili di carico definiscono metriche critiche per il test specifico e modi per modificare i parametri di carico durante il test. Esempi di profili possono essere visti nella figura.

Il testing di carico come servizio CI per gli sviluppatori

Test (test) — uno scenario con un insieme di parametri predefiniti.

Piano di test (test-plan) — un insieme di test e profilo di carico.

Esecuzione del test (testrun) — una iterazione dell'esecuzione di un test con uno scenario di carico completamente eseguito e un rapporto ricevuto.

Richiesta di rete (request) — richiesta HTTP inviata dall'agente alla destinazione.

Risposta di rete (response) — risposta HTTP inviata dalla destinazione all'agente.
Codice di risposta HTTP (HTTP responses status) — codice di risposta standard dal server delle applicazioni.
Transazione (transaction) — ciclo completo "richiesta — risposta". La transazione è considerata dall'inizio dell'invio della richiesta (request) fino al completamento della ricezione della risposta (response).

Stato della transazione (transactions status) — è riuscito a completare con successo il ciclo "richiesta – risposta". Se c'è stato qualche errore in questo ciclo, l'intera transazione è considerata non riuscita.

Tempo di risposta (latency) — tempo dalla fine dell'invio della richiesta (request) all'inizio della ricezione della risposta (response).

Metriche di carico (metrics) — caratteristiche del servizio sotto carico e dell'agente di carico definite durante i test di carico.

Metriche principali per misurare i parametri di carico

Alcune delle metriche più comunemente utilizzate e raccomandate nella metodologia ISTQB (p. 36, 52) sono riportate nella tabella sottostante. Metriche simili per l'agente e l'obiettivo sono indicate nella stessa riga.

Metriche per l'agente di carico
Metriche del sistema o dell'applicazione target, testate sotto carico

Quantità  vCPU e memoria RAM,
Disk — specifiche "hardware" dell'agente di carico
CPU, Memory, Disk usage — dinamica dell'uso della CPU, della memoria e del disco
durante il test. Solitamente misurato in percentuali rispetto ai
valori massimi disponibili

Network throughput (sull'agente di carico) — larghezza di banda
dell'interfaccia di rete sul server,
dove è installato l'agente di carico.
Di solito misurato in byte al secondo (bps)
Network throughput(on target) — larghezza di banda dell'interfaccia di rete
sul server destinato. Di solito misurato in byte al secondo (bps)

Utenti virtuali— numero di utenti virtuali,
che eseguono scenari di carico e
simulano azioni reali degli utenti
Stato degli utenti virtuali, Passato/Fallito/Totale — numero di stati di successo e
falliti del funzionamento degli utenti virtuali
per scenari di carico, insieme al loro numero totale.

Di solito ci si aspetta che tutti gli utenti siano in grado di completare
tutti i propri compiti indicati nel profilo di carico.
Qualsiasi errore significherà che anche l'utente reale non potrà
risolvere il proprio problema mentre lavora con il sistema

Richieste al secondo (minuto)— numero di richieste di rete al secondo (o minuto).

Caratteristica importante dell'agente di carico: quante richieste può generare.
In effetti, è una simulazione dell'interazione con l'applicazione da parte di utenti virtuali
Risposte al secondo (minuto)
— numero di risposte di rete al secondo (o minuto).

Caratteristica importante del servizio di destinazione: quante risposte è riuscito a
generare e inviare come risposte alle richieste da parte
dell'agente di carico

Stato delle risposte HTTP— numero di diversi codici di risposta
dal server dell'applicazione, ricevuto dall'agente di carico.
Ad esempio, 200 OK indica una richiesta andata a buon fine,
mentre 404 indica che la risorsa non è stata trovata.

Latenza (tempo di risposta) — tempo dalla fine
dell'invio della richiesta (request) all'inizio della ricezione della risposta (response).
Di solito viene misurato in millisecondi (ms).

Tempo di risposta della transazione— tempo di una transazione completa,
completamento del ciclo «richiesta — risposta».
Questo tempo va dall'inizio dell'invio della richiesta (request)
alla fine della ricezione della risposta (response).

Il tempo di transazione può essere misurato in secondi (o minuti)
in vari modi: si calcolano il minimo,
il massimo, la media e, ad esempio, il 90° percentile.
Le letture minime e massime sono le condizioni estreme
delle prestazioni del sistema.
Il novantesimo percentile è utilizzato più frequentemente,
poiché mostra la maggior parte degli utenti
che lavorano comodamente al limite delle prestazioni del sistema.

Transazioni al secondo (minuto) — numero totale di
transazioni al secondo (minuto),
cioè quante richieste l'applicazione è riuscita a ricevere e
a elaborare, e fornire risposte.
In effetti, ciò rappresenta la capacità del sistema.

Stato delle transazioni , Passato / Fallito / Totale — numero
transazioni riuscite, non riuscite e totale delle transazioni.

Per gli utenti reali, una transazione non riuscita
significherà effettivamente
l'impossibilità di lavorare con il sistema sotto carico.

Schema fondamentale del test di carico

Lo schema fondamentale del test di carico è molto semplice e consiste in tre fasi principali, di cui ho già parlato: Prepare — Test — Report, ossia la preparazione degli obiettivi di test e la definizione dei parametri per le sorgenti di carico, quindi l'esecuzione dei test di carico e, infine, la generazione e pubblicazione del rapporto di test.

Il testing di carico come servizio CI per gli sviluppatori

Annotazioni sullo schema:

  • QA.Tester — esperto di test di carico,
  • Target — applicazione target, per la quale è necessario conoscere il suo comportamento sotto carico.

Classificatore di entità, fasi e passi nello schema

Fasi e passi
Cosa sta succedendo
Cosa c'è in ingresso
Cosa c'è in uscita

Prepare: fase di preparazione al test

LoadParameters
Definizione e inizializzazione
da parte dell'utente
dei parametri di carico,
selezione delle metriche e
preparazione del piano di test
(profilo di carico)
Parametri utente per
l'inizializzazione dell'agente di carico
Piano di test
Obiettivo del test

VM
Distribuzione nel cloud
macchina virtuale con
specifiche richieste
Parametri VM per l'agente di carico
Script di automazione per
creare VM
VM configurata nel
cloud

Env
Configurazione del sistema operativo e preparazione
dell'ambiente per
lavoro dell'agente di carico
Parametri dell'ambiente per
l'agente di carico
Script di automazione per
impostazioni dell'ambiente
Ambiente preparato:
sistemi operativi, servizi e applicazioni
necessari per il funzionamento
l'agente di carico

LoadAgents
Installazione, configurazione e parametrizzazione
dell'agente di carico.
Oppure scaricamento dell'immagine Docker con
una sorgente di carico preconfigurata
Immagine Docker della sorgente di carico
(YAT, JM o framework personalizzato)
Parametri di configurazione
l'agente di carico
Agente di carico configurato e
pronto per l'uso

Test: fase di esecuzione dei test di carico. Le sorgenti sono agenti di carico distribuiti in pool dedicati per GitLab CI

Load
Avvio dell'agente di carico
con il piano di test selezionato
e parametri di carico
Parametri personalizzati
per l'inizializzazione
l'agente di carico
Piano di test
Obiettivo del test
Log di esecuzione
dei test di carico
Registri di sistema
Dinamica delle metriche obiettivo e dell'agente di carico

RunAgents
Esecuzione dell'agente
di carico degli scenari di test
in conformità con
il profilo di carico
Interazione dell'agente di carico
per scopi di test
Piano di test
Obiettivo del test

Logs
Raccolta di log "grezzi"
nel processo di test del carico:
registrazioni delle azioni dell'agente di carico,
stato dell'obiettivo di test
e della VM su cui è in esecuzione l'agente

Log di esecuzione
dei test di carico
Registri di sistema

Metrics
Raccolta di metriche "grezze" durante il test

Dinamica delle variazioni delle metriche dell'obiettivo
e dell'agente di carico

Report: fase di preparazione del report di test

Generator
Elaborazione delle metriche
e dei log "grezzi" raccolti dal sistema di carico e
dal sistema di monitoraggio
Creazione di un report in
formato leggibile,
possibilmente con elementi di
analisi
Dinamica delle metriche
Log di esecuzione
dei test di carico
Registri di sistema
dell'obiettivo e dell'agente di carico
Log "grezzi" elaborati
in un formato adatto per
l'estrazione verso archivi esterni
Report statico sul carico,
idoneo per analisi da parte di esseri umani
analizzabile dall'uomo

Pubblica
Pubblicazione del report
sul test di carico
in un servizio esterno
Log "grezzi" elaborati
in un formato idoneo
per l'estrazione verso archivi esterni
Report di carico salvati in un
archivio esterno, idonei
per analisi da parte di esseri umani
Collegamento delle fonti di carico nel modello CI
carico, adatti
per l'analisi umana

Connessione delle fonti di carico nel modello CI

Passiamo alla parte pratica. Voglio mostrare come abbiamo implementato la concettualizzazione del testing del carico come servizio in alcuni progetti dell'azienda. Positive Technologies utilizzando la nostra esperienza.

Per prima cosa, il nostro team di ingegneri DevOps ha creato in GitLab CI un pool dedicato di agenti per l'esecuzione dei test di carico. Per evitare confusione con altri pool, come quelli di build, abbiamo aggiunto tag a questi agenti, tags: load. È possibile utilizzare altri tag che siano comprensibili. Questi vengono assegnati durante la registrazione dei GitLab CI Runners.

Come si determina la potenza richiesta per l'hardware? Le caratteristiche degli agenti di carico — un numero sufficiente di vCPU, RAM e Disk — possono essere calcolate tenendo conto che su un agente devono essere in esecuzione Docker, Python (per Yandex.Tank), l'agente GitLab CI e Java (per Apache JMeter). Per Java su JMeter si consiglia inoltre di utilizzare almeno 512 MB di RAM e, come limite massimo, 80% della memoria disponibile..

Pertanto, sulla base della nostra esperienza, raccomandiamo di utilizzare per gli agenti di carico almeno: 4 vCPU, 4 GB di RAM, 60 GB di SSD. La larghezza di banda della scheda di rete viene determinata in base ai requisiti del profilo di carico.

Utilizziamo principalmente due fonti di carico: immagini Docker di Apache JMeter e Yandex.Tank.

Yandex.Tank è uno strumento open-source di Yandex per effettuare test di carico. Alla base della sua architettura modulare c'è un generatore di richieste HTTP ad alte prestazioni chiamato Phantom, che opera in modalità asincrona e basata su hit. Yandex.Tank include il monitoraggio delle risorse del server in test tramite il protocollo SSH, può arrestare automaticamente il test in base a condizioni specifiche e visualizza i risultati sia in console che come grafici; inoltre, è possibile collegare moduli personalizzati per estenderne le funzionalità. A proposito, abbiamo utilizzato Yandex.Tank quando non era ancora di moda. Nell'articolo «Yandex.Tank e automazione dei test di carico» puoi leggere la storia di come nel 2013 abbiamo effettuato test di carico usando questo strumento. PT Application Firewall è uno dei prodotti della nostra azienda.

Apache JMeter JMeter è uno strumento open source per il collaudo delle prestazioni sviluppato da Apache. Può essere utilizzato efficacemente sia per testare applicazioni web statiche che dinamiche. JMeter supporta un'ampia gamma di protocolli e modalità di interazione con le applicazioni: HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET, ecc.), servizi web SOAP/REST, FTP, TCP, LDAP, SMTP(S), POP3(S) e IMAP(S), database tramite JDBC, è in grado di eseguire comandi shell e lavorare con oggetti Java. JMeter dispone di un IDE per creare, debug e eseguire piani di test. È disponibile anche un'interfaccia a riga di comando per operare in qualsiasi sistema operativo compatibile con Java (Linux, Windows, Mac OS X). Lo strumento può generare dinamicamente report HTML sui test.

Per facilitare l'uso all'interno della nostra azienda e per permettere ai tester di modificare e aggiungere ambienti, abbiamo creato build di immagini Docker per i carichi di test su GitLab CI con pubblicazione in un registry Docker interno su Artifactory. Questo rende più veloce e semplice integrarli nei pipeline per i test di carico. Come eseguire il docker push nel registry tramite GitLab CI — consultate il documentazione.

Questo è il file Docker di base per Yandex.Tank:

Dockerfile 
1 | FROM direvius/yandex-tank
2 | ENTRYPOINT [""]

E per Apache JMeter questo:

Dockerfile 
1 | FROM vmarrazzo/jmeter
2 | ENTRYPOINT [""]

Come è organizzato il nostro sistema di integrazione continua, puoi leggerne nell'articolo «Automatizzazione dei processi di sviluppo: come abbiamo implementato le idee DevOps in Positive Technologies».

Modello e pipeline

Un esempio di modello per eseguire test di carico è disponibile nel progetto demo-load. In nel file readme puoi leggere le istruzioni su come utilizzare il modello. Nel modello stesso (file .gitlab-ci.yml) ci sono annotazioni su quale passaggio è responsabile di cosa.

Il modello è molto semplice e dimostra tre fasi del test di carico, descritte sopra nello schema: preparazione, testing e pubblicazione dei report. Queste fasi sono gestite da stages: Prepare, Test e Report.

  1. Fase Prepare dovrebbe essere utilizzata per la configurazione preliminare degli obiettivi di testing o per verificarne la disponibilità. Non è necessario configurare l'ambiente per le fonti di carico, poiché sono già stati creati come immagini Docker e pubblicati nel docker registry: basta specificare la versione necessaria nella fase Test. Ma è possibile ricompilarli e creare le proprie immagini modificate.
  2. Fase Test viene utilizzato per specificare la fonte del carico, avviare i test e conservare gli artefatti di test. È possibile scegliere qualsiasi fonte di carico: Yandex.Tank, Apache JMeter, una propria o tutte insieme. Per disattivare le fonti non necessarie, è sufficiente commentare o eliminare il job. Punti di ingresso per le fonti di carico:

    Nota: il modello di configurazione di build è utilizzato per configurare l'interazione con il sistema CI e non prevede l'inserimento della logica dei test. Per i test viene specificato un punto di ingresso, dove si trova lo script bash di controllo. Il modo di eseguire i test, la generazione di report e gli scenari di test stessi devono essere realizzati dagli ingegneri QA. Nell'esempio demo, per entrambe le fonti di carico, come test più semplice viene utilizzata la richiesta della pagina principale di Yandex. Gli scenari e i parametri dei test si trovano nella directory ./tests.

  3. Nella fase Report È necessario descrivere le modalità di pubblicazione dei risultati dei test ottenuti nella fase di Test su archivi esterni, ad esempio su GitLab Pages o sistemi di reporting specifici. Per GitLab Pages è necessario che, al termine dei test, la cartella ./public non sia vuota e contenga almeno il file index.html. Puoi leggere di più sui dettagli del funzionamento del servizio GitLab Pages al link.

    Esempi di come esportare i dati:

    Istruzioni per la configurazione della pubblicazione:

Nell'esempio demo, il pipeline con i test di carico e due fonti di carico (puoi disattivare quella non necessaria) appare così:

Il testing di carico come servizio CI per gli sviluppatori

Apache JMeter può generare da solo il report in HTML, quindi è più vantaggioso salvarlo in GitLab Pages utilizzando gli strumenti standard. Ecco come appare il report di Apache JMeter:

Il testing di carico come servizio CI per gli sviluppatori

Nell'esempio demo per Yandex.Tank vedrai solo un report di testo fittizio nella sezione per GitLab Pages. Durante il test, Tank può salvare i risultati nel database InfluxDB, da cui possono essere visualizzati, ad esempio, in Grafana (la configurazione avviene nel file ./tests/example-yandextank-test.yml). Ecco come appare il report di Tank in Grafana:

Il testing di carico come servizio CI per gli sviluppatori

Riepilogo

In questo articolo ho parlato del concetto di "load testing as a service" (test di carico come servizio). L'idea principale consiste nell'utilizzare un'infrastruttura di pool di agenti di carico preconfigurati, immagini Docker di sorgenti di carico, sistemi di reportistica e un pipeline che li unisce in GitLab CI basato su un semplice modello .gitlab-ci.yml (esempio al link). Tutto ciò è supportato da un piccolo team di ingegneri automatizzatori e replicato su richiesta dei team di prodotto. Spero che questo vi aiuti nella preparazione e nell'implementazione di uno schema simile nella vostra azienda. Grazie per l'attenzione!

P. S. Vorrei ringraziare i miei colleghi, Sergej Kurbanov e Nikolaj Jusev, per il supporto tecnico nell'implementazione del concetto di load testing as a service nella nostra azienda.

Autore: Timur Gilmullin — vice direttore del dipartimento tecnologie e processi di sviluppo (DevOps) di Positive Technologies

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster