
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 . 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):
Concetti e definizioni fondamentali nel testing delle prestazioni
Durante l'esecuzione dei test di carico, ci sforziamo di seguire , 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 (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.
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 (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.
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. 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, : load. È possibile utilizzare altri tag che siano comprensibili. Questi vengono assegnati 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, .
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.
è 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 «» puoi leggere la storia di come nel 2013 abbiamo effettuato test di carico usando questo strumento. è uno dei prodotti della nostra azienda.
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 . 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 .
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 «».
Modello e pipeline
Un esempio di modello per eseguire test di carico è disponibile nel progetto . In puoi leggere le istruzioni su come utilizzare il modello. Nel modello stesso (file ) 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 : Prepare, Test e Report.
- Fase 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.
- Fase 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:
- i parametri di avvio di Yandex.Tank sono specificati nel file.,
- i parametri di avvio di Apache JMeter sono specificati nel file .
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 .
- Nella fase È 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 .
Esempi di come esportare i dati:
- da JMeter in ,
- da Yandex.Tank in .
Istruzioni per la configurazione della pubblicazione:
- statica HTML in ,
- in InfluxDB e poi in .
Nell'esempio demo, il pipeline con i test di carico e due fonti di carico (puoi disattivare quella non necessaria) appare così:
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:
Nell'esempio demo per Yandex.Tank vedrai solo 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 ). Ecco come appare il report di Tank in Grafana:
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 ). 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: — vice direttore del dipartimento tecnologie e processi di sviluppo (DevOps) di Positive Technologies
Fonte: habr.com
