Mappature delle risorse dall'hardware on-premise a Google Cloud

Questo documento mostra come trovare le mappature delle risorse corrette dall'hardware on-premise a Google Cloud. In uno scenario in cui le tue applicazioni vengono eseguite su server bare-metal e vuoi eseguirne la migrazione a Google Cloud, potresti prendere in considerazione le seguenti domande:

  • In che modo i core fisici (pCPU) vengono mappati alle CPU virtuali (vCPU) su Google Cloud? Ad esempio, come si mappano 4 core fisici di Xeon E5 bare-metal alle vCPU in Google Cloud?
  • Come si tiene conto delle differenze di prestazioni tra le diverse piattaforme CPU e le generazioni di processori? Ad esempio, un Sandy Bridge a 3,0 GHz è 1,5 volte più veloce di uno Skylake a 2,0 GHz?
  • Come dimensionare correttamente le risorse in base ai tuoi carichi di lavoro? Ad esempio, come si ottimizza un'applicazione a thread unico che utilizza molta memoria e in esecuzione su un server multi-core?

Socket, CPU, core e thread

I termini socket, CPU, core e thread vengono spesso utilizzati in modo intercambiabile, il che può causare confusione quando si esegue la migrazione tra ambienti diversi.

In breve, un server può avere uno o più socket. Un socket (chiamato anche socket CPU o slot CPU) è il connettore sulla scheda madre che ospita un chip della CPU e fornisce connessioni fisiche tra la CPU e la scheda di circuito.

Con CPU si intende l'effettivo circuito integrato (IC). Il funzionamento di base di una CPU consiste nell'eseguire una sequenza di instructions memorizzate. A livello generale, le CPU seguono i passaggi di recupero, decodifica ed esecuzione, noti collettivamente come ciclo di istruzione. Nelle CPU più complesse, è possibile recuperare, decodificare ed eseguire contemporaneamente più istruzioni.

Ogni chip della CPU può avere uno o più core. Un core consiste essenzialmente in un'unità di esecuzione che riceve istruzioni ed esegue azioni in base a tali istruzioni. In un sistema iperthread, il core di un processore fisico consente di allocare le risorse come più processori logici. In altre parole, ogni core di processore fisico è presentato come due core virtuali (o logici) nel sistema operativo.

Il seguente diagramma mostra una vista ad alto livello di una CPU quad-core con hyper-threading abilitato.

Una CPU quad-core con hyperthreading abilitato.

In Google Cloud, ogni vCPU viene implementata come un singolo hyper-thread su una delle piattaforme CPU disponibili.

Per trovare il numero totale di vCPU (CPU logiche) nel tuo sistema, puoi utilizzare la formula seguente:

vCPUs = vCPUs × vCPUs × vCPUs

Il comando lscpu raccoglie informazioni che includono il numero di socket, CPU, core e thread. Include inoltre informazioni su cache della CPU e condivisione della cache, famiglia, modello e BogoMips. Ecco un output tipico:

...
Architecture:           x86_64
CPU(s):                 1
On-line CPU(s) list:    0
Thread(s) per core:     1
Core(s) per socket:     1
Socket(s):              1
CPU MHz:                2200.000
BogoMIPS:               4400.00
...

Quando mappi le risorse della CPU tra l'ambiente esistente e Google Cloud, assicurati di conoscere quanti core fisici o virtuali ha il tuo server. Per ulteriori informazioni, consulta la sezione Risorse di mappatura.

Frequenza di clock CPU

Affinché un programma venga eseguito, deve essere suddiviso in un insieme di istruzioni comprensibili per il processore. Prendiamo come esempio il seguente programma C che somma due numeri e mostra il risultato:

#include <stdio.h>
int main()
{
        int a = 11, b = 8;
        printf("%d \n", a+b);
}

Al momento della compilazione, il programma viene convertito nel seguente codice Assembly:

...
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $11, -8(%rbp)
        movl    $8, -4(%rbp)
        movl    -8(%rbp), %edx
        movl    -4(%rbp), %eax
        addl    %edx, %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
...

Ogni istruzione di assemblaggio nell'output precedente corrisponde a una singola istruzione di macchina. Ad esempio, l'istruzione pushq indica che i contenuti del registro RBP devono essere inviati allo stack del programma. Durante ogni ciclo della CPU, una CPU può eseguire un'operazione di base, come recuperare un'istruzione, accedere ai contenuti di un registro o scrivere dati. Per conoscere le fasi del ciclo di aggiunta di due numeri, consulta il Simulatore CPU.

Tieni presente che l'esecuzione di ciascuna istruzione della CPU potrebbe richiedere più cicli di clock. Il numero medio di cicli di clock richiesti per istruzione per un programma è definito da cicli per istruzione (CPI), in questo modo:

cicli per istruzione = numero di cicli di CPU utilizzati / numero di istruzioni eseguite

La maggior parte delle CPU moderne può eseguire più istruzioni per ciclo di clock attraverso la pipeline di istruzioni. Il numero medio di istruzioni eseguite per ciclo è definito dalle istruzioni per ciclo (IPC), in questo modo:

istruzioni per ciclo = numero di istruzioni eseguite / numero di cicli di CPU utilizzati

La frequenza di clock della CPU definisce il numero di cicli di clock che il processore può eseguire al secondo. Ad esempio, un processore a 3,0 GHz può eseguire 3 miliardi di cicli di clock al secondo. Ciò significa che l'esecuzione di ogni ciclo di clock richiede circa 0,3 nanosecondi. Durante ogni ciclo di clock, una CPU può eseguire una o più istruzioni secondo quanto definito dall'IPC.

Le frequenze di clock sono comunemente utilizzate per confrontare le prestazioni del processore. Partendo dalla loro definizione letterale (numero di cicli eseguiti al secondo), potresti concludere che un numero più elevato di cicli di clock significherebbe che la CPU può svolgere più attività e quindi prestazioni migliori. Questa conclusione potrebbe essere valida quando si confrontano le CPU nella stessa generazione del processore. Tuttavia, le frequenze di clock non devono essere utilizzate come unico indicatore delle prestazioni quando si confrontano le CPU di diverse famiglie di processori. Una CPU di nuova generazione potrebbe fornire prestazioni migliori anche se viene eseguita a una frequenza di clock inferiore rispetto alle CPU della generazione precedente.

Frequenze di clock e prestazioni del sistema

Per comprendere meglio le prestazioni di un processore, è importante considerare non solo il numero di cicli di clock, ma anche la quantità di lavoro che una CPU può svolgere in ciascun ciclo. Il tempo totale di esecuzione di un programma legato alla CPU non dipende solo dalla frequenza di clock, ma anche da altri fattori come il numero di istruzioni da eseguire, i cicli per istruzione o istruzioni per ciclo, l'architettura del set di istruzioni, gli algoritmi di pianificazione e di dispatching e il linguaggio di programmazione utilizzato. Questi fattori possono variare significativamente da una generazione all'altra.

Per capire come l'esecuzione della CPU può variare tra due diverse implementazioni, considera l'esempio di un semplice programma fattoriale. Uno dei seguenti programmi è scritto in C e un altro in Python. Perf (uno strumento di profilazione per Linux) viene utilizzato per acquisire alcune metriche di CPU e kernel.

Programma C

#include <stdio.h>
int main()
{
    int n=7, i;
    unsigned int factorial = 1;
    for(i=1; i<=n; ++i){
            factorial *= i;
    }

    printf("Factorial of %d = %d", n, factorial);
}

Performance counter stats for './factorial':

...
0             context-switches       #    0.000 K/sec
0             cpu-migrations         #    0.000 K/sec
45            page-faults            #    0.065 M/sec
1,562,075     cycles                 #    1.28 GHz
1,764,632     instructions           #    1.13  insns per cycle
314,855       branches               #    257.907 M/sec
8,144         branch-misses          #    2.59% of all branches
...

0.001835982 seconds time elapsed

Programma Python

num = 7
factorial = 1
for i in range(1,num + 1):
  factorial = factorial*i
print("The factorial of",num,"is",factorial)

Performance counter stats for 'python3 factorial.py':

...
7              context-switches      #    0.249 K/sec
0              cpu-migrations        #    0.000 K/sec
908            page-faults           #    0.032 M/sec
144,404,306    cycles                #    2.816 GHz
158,878,795    instructions          #    1.10  insns per cycle
38,254,589     branches              #    746.125 M/sec
945,615        branch-misses         #    2.47% of all branches
...

0.029577164 seconds time elapsed

L'output evidenziato mostra il tempo totale impiegato per eseguire ciascun programma. Il programma scritto in C ha eseguito circa 15 volte più velocemente rispetto al programma scritto in Python (1,8 millisecondi contro 30 millisecondi). Ecco alcuni ulteriori confronti:

  • Opzioni di contesto. Quando lo scheduler di sistema deve eseguire un altro programma o quando un'interruzione attiva un'esecuzione in corso, il sistema operativo salva i contenuti del registro della CPU del programma in esecuzione e li configura per la nuova esecuzione del programma. Non si sono verificati cambi di contesto durante l'esecuzione del programma C, ma si sono verificati 7 cambi di contesto durante l'esecuzione del programma Python.

  • Migrazioni di CPU. Il sistema operativo cerca di mantenere il bilanciamento del carico di lavoro tra le CPU disponibili nei sistemi multiprocessore. Questo bilanciamento viene eseguito periodicamente e ogni volta che una coda di esecuzione della CPU è vuota. Durante il test non è stata osservata alcuna migrazione della CPU.

  • Istruzioni. Il programma C ha generato 1,7 milioni di istruzioni eseguite in 1,5 milioni di cicli di CPU (IPC = 1,13, CPI = 0,88), mentre il programma Python ha portato a 158 milioni di istruzioni eseguite in 144 milioni di cicli (IPC = 1,10, CPI = 0,91). Entrambi i programmi hanno riempito la pipeline, consentendo alla CPU di eseguire più di un'istruzione per ciclo. Ma rispetto a C, il numero di istruzioni generate per Python è circa 90 volte maggiore.

  • Errori di pagina. Ogni programma ha una sezione di memoria virtuale contenente tutte le istruzioni e i dati. Generalmente, non è efficiente copiare tutte queste istruzioni nella memoria principale contemporaneamente. Un errore di pagina si verifica ogni volta che un programma ha bisogno di copiare parte del contenuto della sua memoria virtuale nella memoria principale. Un errore di pagina viene segnalato dalla CPU tramite un interruzione.

    Poiché l'interprete eseguibile per Python è molto maggiore di quello per C, l'overhead aggiuntivo è evidente sia in termini di cicli della CPU (1,5 milioni per C, 144 milioni per Python) che per errori di pagina (45 per C, 908 per Python).

  • Filiali e mancati rami. Per le istruzioni condizionali, la CPU cerca di prevedere il percorso di esecuzione ancora prima di valutare la condizione di diramazione. Questo passaggio è utile per mantenere piena la pipeline di istruzioni. Questo processo è chiamato esecuzione speculativa. L'esecuzione speculativa ha avuto un discreto successo nelle esecuzioni precedenti: il predittore di ramo si sbagliava solo il 2,59% delle volte per il programma in C e il 2,47% delle volte per il programma in Python.

Fattori diversi dalla CPU

Finora hai esaminato vari aspetti delle CPU e il loro impatto sulle prestazioni. Tuttavia, è raro che un'applicazione abbia sostenuto l'esecuzione sulla CPU il 100% delle volte. Come semplice esempio, considera il seguente comando tar che crea un archivio dalla directory home di un utente in Linux:

$ time tar cf archive.tar /home/"$(whoami)"

L'output sarà simile al seguente:

real  0m35.798s
user  0m1.146s
sys   0m6.256s

Questi valori di output sono definiti come segue:

in tempo reale
In tempo reale (real) è il tempo necessario per eseguire l'esecuzione dall'inizio alla fine. Questo tempo trascorso include le sezioni di tempo utilizzate da altri processi e il tempo in cui il processo è bloccato, ad esempio quando è in attesa del completamento delle operazioni di I/O.
ora dell'utente
Il tempo utente (user) è la quantità di tempo di CPU dedicata all'esecuzione del codice dello spazio utente nel processo.
ora di sistema
Il tempo di sistema (sys) è la quantità di tempo di CPU impiegata per l'esecuzione del codice dello spazio kernel nel processo.

Nell'esempio precedente, il tempo dell'utente è 1,0 secondi, mentre il tempo del sistema è 6,3 secondi. La differenza di circa 28 secondi tra il tempo di real e il tempo user + sys indica il tempo senza CPU trascorso dal comando tar.

Un tempo fuori CPU elevato per un'esecuzione indica che il processo non è associato alla CPU. Si dice che il calcolo sia vincolato da qualcosa quando la risorsa è il collo di bottiglia per raggiungere le prestazioni previste. Quando pianifichi una migrazione, è importante avere una visione olistica dell'applicazione e considerare tutti i fattori che possono avere un impatto significativo sulle prestazioni.

Ruolo del carico di lavoro di destinazione nella migrazione

Per trovare un punto di partenza ragionevole per la migrazione, è importante eseguire il benchmark delle risorse sottostanti. Puoi eseguire il benchmarking del rendimento in vari modi:

  • Carico di lavoro target effettivo: esegui il deployment dell'applicazione nell'ambiente di destinazione e le prestazioni di benchmark degli indicatori chiave di prestazione (KPI). Ad esempio, i KPI per un'applicazione web possono includere quanto segue:

    • Tempo di caricamento dell'applicazione
    • Latenze dell'utente finale per le transazioni end-to-end
    • Connessioni eliminate
    • Numero di istanze di gestione per traffico ridotto, medio e picco
    • Utilizzo delle risorse (CPU, RAM, disco, rete) delle istanze di gestione

    Tuttavia, il deployment di un'applicazione di destinazione completa (o di un sottoinsieme di) può essere complesso e dispendioso in termini di tempo. Per il benchmarking preliminare, sono generalmente preferiti benchmark basati sul programma.

  • Benchmark basati sul programma: i benchmark basati sul programma si concentrano sui singoli componenti dell'applicazione anziché sul flusso dell'applicazione end-to-end. Questi benchmark eseguono una combinazione di profili di test, in cui ogni profilo ha come target un componente dell'applicazione. Ad esempio, i profili di test per un deployment di LAMP stack possono includere Apache Bench, che viene utilizzato per confrontare le prestazioni del server web, e Sysbench, che viene utilizzato per confrontare MySQL. Questi test sono generalmente più facili da configurare rispetto ai carichi di lavoro target effettivi e sono molto portabili in diversi sistemi operativi e ambienti.

  • Benchmark del kernel o sintetici: per testare aspetti delle chiavi con uso intensivo di calcolo da programmi reali, puoi utilizzare benchmark sintetici come la scomposizione matriciale o FFT. In genere questi test vengono eseguiti durante la fase iniziale di progettazione dell'applicazione. Sono particolarmente adatti per il benchmarking solo di determinati aspetti di una macchina, come le sollecitazioni delle VM e dell'unità, le sincronizzazioni I/O e il thrashing della cache.

Comprendere l'applicazione

Molte applicazioni sono vincolate da CPU, memoria, I/O del disco e I/O di rete o da una combinazione di questi fattori. Ad esempio, se un'applicazione sta riscontrando una lentezza a causa della contesa sui dischi, fornire più core ai server potrebbe non migliorare le prestazioni.

Tieni presente che mantenere l'osservabilità delle applicazioni in ambienti complessi e di grandi dimensioni può non essere banale. Esistono sistemi di monitoraggio specializzati in grado di tenere traccia di tutte le risorse distribuite a livello di sistema. Ad esempio, su Google Cloud puoi utilizzare Cloud Monitoring per ottenere una visibilità completa su codice, applicazioni e infrastruttura. Un esempio di Cloud Monitoring viene discusso più avanti in questa sezione, ma prima è una buona idea comprendere il monitoraggio delle risorse di sistema tipiche su un server autonomo.

Molte utilità, come top, IOStat, VMStat e iPerf, sono in grado di fornire una visione generale delle risorse di un sistema. Ad esempio, l'esecuzione di top su un sistema Linux produce un output come questo:

top - 13:20:42 up 22 days,  5:25,         18 users,        load average: 3.93 2.77,3.37
Tasks:  818 total,        1 running,      760 sleeping,    0 stopped,       0 zombie
Cpu(s): 88.2%us,          0.0%sy,         0.0%ni,          0.3%id,          0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem:    49375504k total,  6675048k used,  42700456k free,  276332k buffers
Swap:   68157432k total,  0k used,        68157432k free,  5163564k cached

Se il sistema ha un carico elevato e la percentuale del tempo di attesa è elevata, probabilmente hai un'applicazione vincolata a I/O. Se uno o entrambi i valori del tempo percentuale di utenti o di sistema sono molto elevati, probabilmente hai un'applicazione vincolata alla CPU.

Nell'esempio precedente, le medie di carico (per una VM con 4 vCPU) negli ultimi 5 minuti, 10 minuti e 15 minuti sono rispettivamente 3,93, 2,77 e 3,37. Se combini queste medie con l'alta percentuale di tempo utente (88,2%), il tempo di inattività ridotto (0,3%) e l'assenza di tempo di attesa (0,0%), puoi concludere che il sistema è vincolato alla CPU.

Sebbene questi strumenti funzionino bene per i sistemi autonomi, in genere non sono progettati per monitorare ambienti distribuiti di grandi dimensioni. Per monitorare i sistemi di produzione, strumenti come Cloud Monitoring, Nagios, Prometheus e Sysdig possono fornire un'analisi approfondita del consumo delle risorse rispetto alle tue applicazioni.

Il monitoraggio delle prestazioni della tua applicazione per un periodo di tempo sufficiente consente di raccogliere dati su più metriche, ad esempio utilizzo della CPU, utilizzo della memoria, I/O del disco, I/O della rete, tempi di round trip, latenze, percentuali di errore e velocità effettiva. Ad esempio, i seguenti grafici di Cloud Monitoring mostrano i livelli di utilizzo e i carichi della CPU, insieme all'utilizzo di memoria e disco per tutti i server in esecuzione in un gruppo di istanze gestite di Google Cloud. Per ulteriori informazioni su questa configurazione, consulta la panoramica dell'agente Cloud Monitoring.

Carichi della CPU, livelli di utilizzo e utilizzo di memoria e disco per tutti i server in esecuzione in un gruppo di istanze gestite.

Per l'analisi, il periodo di raccolta dei dati dovrebbe essere abbastanza lungo da mostrare il picco e l'utilizzo minimo delle risorse. Puoi quindi analizzare i dati raccolti per fornire un punto di partenza per la pianificazione della capacità nel nuovo ambiente di destinazione.

Risorse della mappa

Questa sezione illustra come stabilire il dimensionamento delle risorse su Google Cloud. In primo luogo, effettui una valutazione iniziale delle dimensioni in base ai livelli di utilizzo delle risorse esistenti. Poi esegui test di benchmarking delle prestazioni specifici dell'applicazione.

Dimensionamento basato sull'utilizzo

Segui questi passaggi per mappare il conteggio dei core esistenti di un server alle vCPU in Google Cloud.

  1. Trova il numero di core attuali. Fai riferimento al comando lscpu nella sezione precedente

  2. Individua l'utilizzo della CPU da parte del server. L'utilizzo della CPU si riferisce al tempo impiegato dalla CPU quando è in modalità utente (%us) o modalità kernel (%sy). Anche i processi piacevoli (%ni) appartengono alla modalità utente, mentre le interruzioni software (%si) e gli interruzioni hardware (%hi) vengono gestiti in modalità kernel. Se la CPU non esegue queste operazioni, significa che è inattiva o è in attesa del completamento dell'I/O. Quando un processo è in attesa del completamento dell'I/O, non contribuisce ai cicli della CPU.

    Per calcolare l'utilizzo attuale della CPU di un server, esegui questo comando top:

    ...
    Cpu(s): 88.2%us,  0.0%sy,  0.0%ni,  0.3%id,  0.0%wa,  0.0%hi,  0.0%si, 0.0%st
    ...
    

    L'utilizzo della CPU è definito come segue:

    CPU Usage = %us + %sy + %ni + %hi + %si
    

    In alternativa, puoi utilizzare qualsiasi strumento di monitoraggio come Cloud Monitoring in grado di raccogliere l'inventario e l'utilizzo della CPU richiesti. Per i deployment delle applicazioni senza scalabilità automatica (ovvero, eseguiti con uno o più server fissi), ti consigliamo di considerare l'utilizzo dei picchi di utilizzo per il dimensionamento della CPU. Questo approccio salvaguarda le risorse delle applicazioni dalle interruzioni quando i carichi di lavoro raggiungono i picchi di utilizzo. Per i deployment con scalabilità automatica (in base all'utilizzo della CPU), l'utilizzo medio della CPU è una base di riferimento sicura da considerare per le dimensioni. In questo caso, puoi gestire i picchi di traffico effettuando lo scale out del numero di server per tutta la durata del picco.

  3. Assegna una quantità di buffer sufficiente per far fronte ai picchi. Quando ridimensioni la CPU, includi un buffer sufficiente per ospitare eventuali elaborazioni non pianificate che potrebbero causare picchi imprevisti. Ad esempio, puoi pianificare la capacità della CPU in modo che ci sia un margine aggiuntivo del 10-15% rispetto all'utilizzo massimo previsto e che l'utilizzo massimo complessivo della CPU non superi il 70%.

  4. Utilizza la seguente formula per calcolare il numero previsto di core su Google Cloud:

    vCPU su Google Cloud = 2 × CEILING[(conteggio-core × %di utilizzo) / (2 × %soglia)]

    Questi valori sono definiti come segue:

    • core-count: il numero di core esistenti (calcolato nel passaggio 1).
    • utilization%: l'utilizzo della CPU da parte del server (calcolato nel passaggio 2).
    • threshold%: l'utilizzo massimo della CPU consentito sul server dopo aver preso in considerazione un margine sufficiente (come calcolato nel passaggio 3).

Per un esempio concreto, considera uno scenario in cui devi mappare il conteggio dei core di un server Xeon E5640 a quattro core bare-metal in esecuzione on-premise sulle vCPU in Google Cloud. Le specifiche dello Xeon E5640 sono disponibili pubblicamente, ma puoi anche confermarle eseguendo un comando come lscpu sul sistema. I numeri hanno il seguente aspetto:

  • numero di core esistenti on-premise = socket (1) × core (4) × thread per core (2) = 8.
  • Supponiamo che l'utilizzo della CPU (utilization%) osservato durante il traffico di picco sia pari al 40%.
  • È previsto un buffer aggiuntivo del 30%, ovvero l'utilizzo massimo della CPU (threshold%) non deve superare il 70%.
  • vCPU su Google Cloud = 2 × ARROTONDA.ECCESSO[(8 × 0,4)/(2 × 0,7)] = 6 vCPU
    (vale a dire 2 × CEILING[3,2/1,4] = 2 × CEILING[2,28] = 2 × 3 = 6)

Puoi eseguire valutazioni simili per RAM, disco, I/O di rete e altre risorse di sistema.

Dimensionamento basato sulle prestazioni

Nella sezione precedente sono stati trattati i dettagli della mappatura di pCPU alle vCPU in base ai livelli di utilizzo attuali e previsti della CPU. Questa sezione prende in considerazione l'applicazione in esecuzione sul server.

In questa sezione, eseguirai un insieme canonico standard di test (benchmark basati sul programma) per confrontare il rendimento. Proseguendo con lo scenario di esempio, considera che stai eseguendo un server MySQL sulla macchina Xeon E5. In questo caso, puoi utilizzare Sysbench OLTP per eseguire il benchmark delle prestazioni del database.

Un semplice test di lettura-scrittura su MySQL utilizzando Sysbench produce il seguente output:

OLTP test statistics:
  queries performed:
    read:              520982
    write:             186058
    other:             74424
    total:             781464
  transactions:        37211 (620.12 per sec.)
  deadlocks:           2 (0.03 per sec.)
  read/write requests: 707040 (11782.80 per sec.)
  other operations:    74424 (1240.27 per sec.)

Test execution summary:
  total time:          60.0061s
  total number of events: 37211
  total time taken by event execution: 359.8158
  per-request statistics:
    min:            2.77ms
    avg:            9.67ms
    max:            50.81ms
    approx. 95 percentile: 14.63ms

Thread fairness:
  events (avg/stddev):         6201.8333/31.78
  execution time (avg/stddev): 59.9693/0.00

L'esecuzione di questo benchmark consente di confrontare le prestazioni in termini di numero di transazioni al secondo, letture/scritture totali al secondo e tempo di esecuzione end-to-end tra il tuo ambiente attuale e Google Cloud. Ti consigliamo di eseguire più iterazioni di questi test per escludere eventuali anomalie. Per osservare le differenze di prestazioni in base a diversi modelli di carico e traffico, puoi anche ripetere questi test con parametri diversi, ad esempio livelli di contemporaneità, durata dei test e numero di utenti simulati o diverse frequenze di hatch.

I valori relativi alle prestazioni tra l'ambiente attuale e Google Cloud aiuteranno a razionalizzare ulteriormente la valutazione iniziale della capacità. Se i test di benchmark su Google Cloud restituiscono risultati simili o migliori rispetto all'ambiente esistente, puoi regolare ulteriormente la scala delle risorse in base ai miglioramenti nelle prestazioni. Se invece i benchmark sul tuo ambiente esistente sono migliori che su Google Cloud, devi procedere come segue:

  • Rivedi la valutazione iniziale della capacità.
  • Monitorare le risorse di sistema.
  • Individua le possibili aree di contesa (ad esempio, i colli di bottiglia identificati su CPU e RAM).
  • Ridimensiona le risorse di conseguenza.

Al termine, esegui nuovamente i test di benchmark specifici per l'applicazione.

Benchmarking del rendimento end-to-end

Finora hai esaminato uno scenario semplicistico che confronta solo le prestazioni di MySQL tra on-premise e Google Cloud. In questa sezione, prenderai in considerazione la seguente applicazione a tre livelli distribuita.

Applicazione distribuita a 3 livelli.

Come mostra il diagramma, probabilmente hai eseguito più benchmark per raggiungere una valutazione ragionevole del tuo ambiente attuale e di Google Cloud. Tuttavia, può essere difficile stabilire quale sottoinsieme di benchmark stima le prestazioni dell'applicazione in modo più accurato. Inoltre, gestire il processo di test può essere noioso, dalla gestione delle dipendenze all'installazione dei test, all'esecuzione e all'aggregazione dei risultati in ambienti cloud o non cloud diversi. In questi casi, puoi utilizzare PerfKitBenchmarker. PerfKit contiene vari set di benchmark per misurare e confrontare le diverse offerte su più cloud. Può inoltre eseguire determinati benchmark on-premise tramite macchine statiche.

Supponiamo che per l'applicazione a tre livelli nel diagramma precedente tu voglia eseguire dei test per confrontare il tempo di avvio del cluster, la CPU e le prestazioni di rete delle VM su Google Cloud. Utilizzando PerfKitBenchmarker, puoi eseguire più iterazioni di profili di test pertinenti, che generano i seguenti risultati:

  • Tempo di avvio del cluster: fornisce una visualizzazione del tempo di avvio delle VM. Ciò è particolarmente importante se l'applicazione è elastica e prevede che le istanze vengano aggiunte o rimosse nell'ambito della scalabilità automatica. Il seguente grafico mostra che i tempi di avvio di un'istanza di n1-standard-4 Compute Engine rimangono abbastanza coerenti (fino al 99° percentile) a 40-45 secondi.

    Tempi di avvio di un'istanza Compute Engine n1-standard-4.

  • Stress-ng: misura e confronta le prestazioni ad alta intensità di calcolo, sottolineando il processore, il sottosistema di memoria e il compilatore di un sistema. Nel seguente esempio, stress-ng esegue più stress test come bsearch, malloc, matrix, mergesort e zlib su un'istanza di Compute Engine n1-standard-4. Stress-ng misura la velocità effettiva dei test di stress utilizzando operazioni fasulle (operazioni bogo) al secondo. Se normalizzi le operazioni bogo in diversi risultati dello stress test, ottieni il seguente output, che mostra la media geometrica delle operazioni eseguite al secondo. In questo esempio, le operazioni bogo vanno da circa 8000 al secondo al 50° percentile a circa 10.000 al secondo al 95° percentile. Tieni presente che le operazioni bogo vengono generalmente utilizzate per confrontare solo le prestazioni della CPU autonoma. Queste operazioni potrebbero non essere rappresentative della tua applicazione.

    Media geometrica delle operazioni eseguite al secondo.

  • Netperf: misura la latenza con test di richieste e risposte. I test di richieste e risposte vengono eseguiti a livello di applicazione dello stack di rete. Questo metodo di test di latenza coinvolge tutti i livelli dello stack ed è preferito rispetto ai test di ping per misurare la latenza da VM a VM. Il seguente grafico mostra le latenze di richiesta e risposta TCP (TCP_RR) tra un client e un server in esecuzione nella stessa zona Google Cloud. I valori TCP_RR vanno da circa 70 microsecondi al 50° percentile a ~130 microsecondi al 90° percentile.

    Latenze di richiesta e risposta TCP tra client e server in esecuzione nella stessa zona Google Cloud.

Data la natura del carico di lavoro di destinazione, puoi eseguire altri profili di test utilizzando PerfKit. Per i dettagli, consulta i Benchmark supportati in PerfKit.

Best practice su Google Cloud

Prima di configurare ed eseguire un piano di migrazione su Google Cloud, ti consigliamo di seguire le best practice per la migrazione. Queste pratiche sono solo un punto di partenza. Potrebbe essere necessario considerare molti altri aspetti dell'applicazione, come il disaccoppiamento delle dipendenze, l'introduzione della tolleranza di errore e lo scale up e lo scale down in base al carico di lavoro dei componenti, nonché il modo in cui ciascuno di questi aspetti viene mappato a Google Cloud.

  1. Conoscere i limiti e le quote di Google Cloud. Prima di iniziare formalmente con la valutazione della capacità, comprendi alcune considerazioni importanti per la pianificazione delle risorse su Google Cloud, ad esempio:

    Elencare i componenti di Infrastructure as a Service (IaaS) e Platform as a Service (PaaS) che sarebbero necessari durante la migrazione e comprendere chiaramente eventuali quote, limiti ed eventuali aggiustamenti di ottimizzazione disponibili per ciascuno dei servizi.

  2. Monitora le risorse continuamente. Il monitoraggio continuo delle risorse può aiutarti a identificare pattern e tendenze nelle prestazioni del sistema e delle applicazioni. Il monitoraggio non solo consente di stabilire le prestazioni di base, ma dimostra anche la necessità di upgrade e downgrade dell'hardware nel tempo. Google Cloud offre varie opzioni per il deployment di soluzioni di monitoraggio end-to-end:

  3. Dimensioni giuste delle VM. Identifica quando è presente un provisioning insufficiente o in overprovisioning di una VM. La configurazione del monitoraggio di base come spiegato in precedenza dovrebbe fornire facilmente questi insight. Google Cloud fornisce inoltre suggerimenti per il dimensionamento ottimale basati sull'utilizzo storico di un'istanza. Inoltre, a seconda della natura del carico di lavoro, se i tipi di macchine predefinite non soddisfano le tue esigenze, puoi creare un'istanza con impostazioni hardware virtualizzate personalizzate.

  4. Usa gli strumenti giusti. Per ambienti su larga scala, esegui il deployment di strumenti automatizzati per ridurre al minimo lo sforzo manuale, ad esempio:

Concetti chiave

La migrazione delle risorse da un ambiente a un altro richiede un'attenta pianificazione. È importante non considerare le risorse hardware in modo isolato, ma avere una visione end-to-end dell'applicazione. Ad esempio, anziché focalizzarti esclusivamente sulla velocità doppia di un processore Sandy Bridge a 3,0 GHz rispetto a un processore Skylake da 1,5 GHz, concentrati sul modo in cui gli indicatori chiave delle prestazioni dell'applicazione cambiano da una piattaforma di elaborazione all'altra.

Quando valuti i requisiti di mappatura delle risorse in ambienti diversi, considera quanto segue:

  • Le risorse di sistema su cui è vincolata l'applicazione (ad esempio CPU, memoria, disco o rete).
  • Impatto dell'infrastruttura sottostante (ad esempio generazione del processore, velocità di clock, HDD o SSD) sulle prestazioni della tua applicazione.
  • Impatto delle scelte di progettazione del software e dell'architettura (ad esempio, carichi di lavoro con thread singolo o multithread, deployment fissi o con scalabilità automatica) sulle prestazioni dell'applicazione.
  • Livelli di utilizzo attuali e previsti delle risorse di computing, archiviazione e rete.
  • Test delle prestazioni più appropriati che sono rappresentativi della tua applicazione.

La raccolta dei dati in base a queste metriche attraverso il monitoraggio continuo consente di determinare un piano di capacità iniziale. Puoi verificare con un benchmarking adeguato del rendimento per perfezionare le stime delle dimensioni iniziali.

Passaggi successivi