Mapper des ressources à partir de matériel sur site vers Google Cloud

Ce document vous explique comment identifier les mappages adaptés des ressources à partir du matériel sur site vers Google Cloud. Dans un scénario où vos applications s'exécutent sur des serveurs physiques et où vous souhaitez les migrer vers Google Cloud, vous pouvez vous poser les questions suivantes :

  • Comment les cœurs physiques (processeurs physiques) sont-ils mappés aux processeurs virtuels sur Google Cloud ? Par exemple, comment mapper quatre cœurs physiques de Xeon E5 à des processeurs virtuels dans Google Cloud ?
  • Comment prendre en compte les différences de performances entre les différentes plates-formes de processeur et générations de processeur ? Par exemple, un Sandy Bridge de 3 GHz est-il 1,5 fois plus rapide qu'un Skylake de 2 GHz ?
  • Comment dimensionner les ressources en fonction des charges de travail ? Par exemple, comment peut-on optimiser une application monothread qui nécessite une utilisation intensive de la mémoire et qui s'exécute sur un serveur multicœur ?

Sockets, processeurs, cœurs et threads

Les termes socket, processeur, cœur et thread sont souvent utilisés de manière interchangeable, ce qui peut prêter à confusion lorsque vous effectuez des migrations entre différents environnements.

En bref, un serveur peut avoir un ou plusieurs sockets. Un socket (également appelé support du processeur ou réceptacle de processeur) est le connecteur de la carte mère qui héberge un processeur physique et fournit des connexions physiques entre le processeur et le circuit imprimé.

Le terme "processeur" fait référence au circuit intégré réel. L'opération essentielle d'un processeur consiste à exécuter une séquence d'instructions stockées. De manière générale, les processeurs suivent les étapes d'extraction, de décodage et d'exécution, collectivement appelées cycle d'instructions. Dans les processeurs les plus complexes, plusieurs instructions peuvent être extraites, décodées et exécutées simultanément.

Chaque processeur physique peut avoir un ou plusieurs cœurs. Un cœur se compose essentiellement d'une unité d'exécution qui reçoit des instructions et effectue des actions en fonction de ces instructions. Dans un système d'hyper-threading, un cœur de processeur physique permet d'allouer ses ressources en tant que processeurs logiques multiples. En d'autres termes, chaque cœur de processeur physique est présenté comme deux cœurs virtuels (ou logiques) au système d'exploitation.

Le schéma suivant montre une vue d'ensemble d'un processeur à quatre cœurs avec l'hyper-threading activé.

Processeur à quatre cœurs avec l'hyper-threading activé

Dans Google Cloud, chaque processeur virtuel est mis en œuvre sous la forme d'un hyper-thread unique sur l'une des plates-formes de processeur disponibles.

Vous pouvez identifier le nombre total de processeurs virtuels de votre système à l'aide de la formule suivante :

Processeurs virtuels = nombre de threads par cœur physique × cœurs physiques par socket × nombre de sockets

La commande lscpu rassemble des informations qui incluent le nombre de sockets, de processeurs, de cœurs et de threads. Elle comprend également des informations sur les caches de processeur et la famille, le modèle, le BogoMips et le partage des caches. Voici un exemple de résultat :

...
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
...

Lorsque vous mappez des ressources de processeur entre votre environnement existant et Google Cloud, assurez-vous de connaître le nombre de cœurs physiques ou virtuels de votre serveur. Pour en savoir plus, consultez la section Mapper des ressources.

Fréquence d'horloge du processeur

Pour qu'un programme s'exécute, il doit être divisé en un ensemble d'instructions que le processeur peut comprendre. Prenons l'exemple du programme en C suivant qui additionne deux nombres et affiche le résultat :

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

Lors de la compilation, le programme est converti en code d'assemblage :

...
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
...

Chaque instruction d'assemblage du résultat précédent correspond à une seule instruction de la machine. Par exemple, l'instruction pushq indique que le contenu du registre RBP doit être transféré dans la pile de programmes. Au cours de chaque cycle de processeur, un processeur peut effectuer une opération de base telle que l'extraction d'une instruction, l'accès au contenu d'un registre ou l'écriture de données. Pour parcourir chaque étape du cycle de l'addition de deux nombres, consultez ce simulateur de processeur.

Notez que chaque instruction du processeur peut nécessiter plusieurs cycles d'horloge pour s'exécuter. Pour un programme, le nombre moyen de cycles d'horloge requis par instruction est défini par le nombre de cycles par instruction (CPI), comme suit :

Nombre de cycles par instruction = nombre de cycles de processeur utilisés / nombre d'instructions exécutées

La plupart des processeurs modernes peuvent exécuter plusieurs instructions par cycle d'horloge via le pipeline. Le nombre moyen d'instructions exécutées par cycle est défini par le nombre d'instructions par cycle (IPC), comme suit :

Nombre d'instructions par cycle = nombre d'instructions exécutées / nombre de cycles de processeur utilisés

La fréquence d'horloge du processeur définit le nombre de cycles d'horloge que le processeur peut exécuter par seconde. Par exemple, un processeur de 3 GHz peut exécuter 3 milliards de cycles d'horloge par seconde. Cela signifie que chaque cycle d'horloge prend environ 0,3 nanoseconde. À chaque cycle d'horloge, un processeur peut exécuter une ou plusieurs instructions, telles que définies par l'IPC.

Les fréquences d'horloge sont généralement utilisées pour comparer les performances des processeurs. En suivant leur définition littérale (nombre de cycles exécutés par seconde), vous pourriez en conclure qu'un nombre plus élevé de cycles d'horloge signifierait que le processeur peut effectuer davantage de travail et donc afficher de meilleures performances. Cette conclusion peut être valide lorsque vous comparez des processeurs appartenant à une même génération. Toutefois, les fréquences d'horloge ne doivent pas être utilisées comme seul indicateur de performance lorsque vous comparez les processeurs provenant de différentes familles de processeurs. Un processeur de nouvelle génération peut offrir de meilleures performances même lorsqu'il s'exécute à une fréquence d'horloge inférieure à celle des processeurs de générations précédentes.

Fréquence d'horloge et performances du système

Pour mieux comprendre les performances d'un processeur, il est important d'examiner non seulement le nombre de cycles d'horloge, mais également la quantité de travail qu'un processeur peut effectuer par cycle. La durée totale d'exécution d'un programme lié au processeur dépend non seulement de la fréquence d'horloge, mais également d'autres facteurs, tels que le nombre d'instructions à exécuter, le nombre de cycles par instruction ou d'instructions par cycle, l'architecture de l'ensemble d'instructions, les algorithmes d'ordonnancement et de répartition, ainsi que le langage de programmation utilisé. Ces facteurs peuvent varier considérablement d'une génération de processeur à l'autre.

Pour comprendre comment l'exécution d'un processeur peut varier entre deux implémentations différentes, prenons l'exemple d'un programme factoriel simple. L'un des programmes suivants est écrit en C et l'autre en Python. Perf (outil de profilage pour Linux) est utilisé pour capturer certaines métriques du processeur et du noyau.

Programme en 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

Programme en 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

Le résultat en surbrillance indique la durée totale d'exécution de chaque programme. Le programme écrit en C s'exécute environ 15 fois plus rapidement que celui écrit en Python (1,8 milliseconde contre 30 millisecondes). Voici quelques comparaisons supplémentaires :

  • Changements de contexte : lorsque le programmeur système doit exécuter un autre programme ou lorsqu'une interruption déclenche une exécution continue, le système d'exploitation enregistre le contenu du registre du processeur du programme en cours d'exécution et le configure pour la nouvelle exécution du programme. Aucun changement de contexte n'est survenu lors de l'exécution du programme en C, mais sept changements de contexte se sont produits lors de l'exécution du programme en Python.

  • Migrations de processeurs : le système d'exploitation tente de maintenir un équilibrage de charge de travail entre les processeurs disponibles dans les systèmes multiprocesseurs. Cet équilibrage est effectué régulièrement et à chaque fois qu'une file d'attente d'exécution de processeur est vide. Pendant le test, aucune migration de processeur n'a été constatée.

  • Instructions : le programme en C a généré 1,7 million d'instructions qui ont été exécutées en 1,5 million de cycles de processeur (IPC = 1,13 ; CPI = 0,88), tandis que le programme en Python en a généré 158 millions en 144 millions de cycles (IPC = 1,10 ; CPI = 0,91). Les deux programmes ont rempli le pipeline, permettant au processeur d'exécuter plus d'une instruction par cycle. Toutefois, par rapport au programme en C, le nombre d'instructions générées pour le programme en Python est environ 90 fois plus élevé.

  • Défauts de page : chaque programme dispose d'une tranche de mémoire virtuelle contenant toutes ses instructions et données. En général, il n'est pas efficace de copier toutes ces instructions dans la mémoire principale en une seule fois. Un défaut de page se produit chaque fois qu'un programme doit copier une partie du contenu de sa mémoire virtuelle dans la mémoire principale. Un défaut de page est signalé par le processeur via une interruption.

    Étant donné que l'interprète exécutable pour Python est beaucoup plus volumineux que pour C, la charge supplémentaire est évidente aussi bien en matière de cycles de processeur (1,5 M pour C, 144 M pour Python) que de défauts de page (45 pour C, 908 pour Python).

  • Branches et branches manquées : pour les instructions conditionnelles, le processeur tente de prédire le chemin d'exécution avant même d'évaluer la condition de branchement. Une telle étape est utile pour s'assurer que le pipeline est toujours plein. Ce processus est appelé exécution spéculative. L'exécution spéculative a rencontré un grand succès dans les exécutions précédentes : le prédicteur de branche ne s'est trompé que 2,59 % du temps pour le programme en C et 2,47 % du temps pour le programme en Python.

Facteurs autres que le processeur

Jusqu'à présent, nous avons examiné divers aspects des processeurs et leur impact sur les performances. Cependant, il est rare qu'une application ait une exécution sur processeur à 100 % du temps. Prenons comme exemple simple la commande tar suivante qui crée une archive à partir du répertoire home d'un utilisateur sous Linux :

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

Le résultat ressemble à ceci :

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

Ces valeurs de sortie sont définies comme suit :

Temps réel
Le temps réel (real) correspond au temps nécessaire à l'exécution, du début à la fin. Ce temps écoulé inclut les tranches horaires utilisées par d'autres processus ainsi que les moments où le processus est bloqué, par exemple lorsqu'il attend la fin des opérations d'E/S.
Durée utilisateur
La durée utilisateur (user) correspond au temps CPU passé à exécuter le code de l'espace utilisateur dans le processus.
Durée système
La durée système (sys) correspond au temps CPU passé à exécuter le code d'espace de noyau dans le processus.

Dans l'exemple précédent, la durée utilisateur est de 1,0 seconde, tandis que la durée système est de 6,3 secondes. La différence d'environ 28 secondes entre real et user + sys indique le temps hors CPU pris par la commande tar.

Un temps hors CPU élevé pour une exécution indique que le processus n'est pas lié au processeur. Un calcul est lié à une ressource lorsque celle-ci représente le goulot d'étranglement pour atteindre les performances attendues. Lorsque vous planifiez une migration, il est important d'avoir une vision globale de l'application et de prendre en compte tous les facteurs pouvant avoir un impact significatif sur les performances.

Rôle de la charge de travail cible dans la migration

Afin de trouver un point de départ raisonnable pour la migration, il est important de comparer les ressources sous-jacentes. Vous pouvez effectuer une analyse comparative des performances de différentes manières :

  • Charge de travail cible réelle : déployez l'application dans l'environnement cible et comparez les performances des indicateurs clés de performance (KPI, Key Performance Indicators). Par exemple, les KPI d'une application Web peuvent inclure les éléments suivants :

    • Temps de chargement de l'application
    • Latences des utilisateurs finaux pour les transactions de bout en bout
    • Connexions supprimées
    • Nombre d'instances de diffusion pour un trafic faible, moyen et maximal
    • Utilisation des ressources (processeur, RAM, disque, réseau) des instances de diffusion

    Cependant, le déploiement d'une application cible complète (ou d'un sous-ensemble de celle-ci) peut être complexe et chronophage. Dans le cas d'une analyse comparative préliminaire, les analyses comparatives basées sur les programmes sont généralement privilégiées.

  • Analyses comparatives basées sur les programmes : elles se concentrent sur les composants individuels de l'application plutôt que sur le processus de bout en bout. Ces analyses comparatives exécutent une combinaison de profils de test, chaque profil étant ciblé sur un composant de l'application. Par exemple, les profils de test d'un déploiement de pile LAMP peuvent inclure Apache Bench, qui permet de comparer les performances du serveur Web, et Sysbench, qui est utilisé pour analyser MySQL. Ces tests sont généralement plus faciles à configurer que les charges de travail cibles réelles et bénéficient d'un bon portage sur différents systèmes d'exploitation et environnements.

  • Analyses comparatives synthétiques ou du noyau : des analyses comparatives synthétiques telles que la factorisation matricielle ou FFT vous permettent de tester des aspects clés qui utilisent des ressources de calcul importantes à partir de programmes réels. Ces tests sont généralement exécutés dès le début de la phase de conception de l'application. Ils sont particulièrement adaptés à l'analyse comparative de certains aspects d'une machine, tels que la contrainte de disque et de VM, les synchronisations d'E/S et le thrashing du cache.

Comprendre votre application

De nombreuses applications sont liées au processeur, à la mémoire, aux E/S disque et aux E/S réseau, ou à une combinaison de ces facteurs. Par exemple, si une application rencontre des problèmes de lenteur en raison de conflits sur les disques, fournir davantage de cœurs aux serveurs peut ne pas améliorer les performances.

Notez que la maintenance de l'observabilité des applications dans des environnements complexes et volumineux peut ne pas constituer une tâche triviale. Il existe des systèmes de surveillance spécialisés qui permettent d'effectuer le suivi de toutes les ressources distribuées à l'échelle du système. Par exemple, sur Google Cloud, Cloud Monitoring peut vous permettre d'obtenir une visibilité totale sur votre code, vos applications et votre infrastructure. Un exemple de l'utilisation de Cloud Monitoring est abordé plus loin dans cette section. Cependant, il est tout d'abord judicieux de comprendre la surveillance des ressources système types sur un serveur autonome.

De nombreux utilitaires, tels que top, IOStat, VMStat et iPerf, peuvent fournir une vue d'ensemble des ressources du système. Par exemple, l'exécution de top sur un système Linux produit un résultat semblable à celui-ci :

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

Si le système présente une charge élevée et que le pourcentage de temps d'attente est lui aussi élevé, l'application est probablement liée aux E/S. Si le pourcentage de la durée utilisateur et/ou de la durée système est très élevé, l'application est probablement liée au processeur.

Dans l'exemple précédent, les moyennes de charge (pour une VM à 4 processeurs virtuels) au cours des 5, 10 et 15 dernières minutes sont respectivement 3,93, 2,77 et 3,77. Si l'on combine ces moyennes au pourcentage élevé de durée utilisateur (88,2 %), au faible temps d'inactivité (0,3 %) et au temps d'attente nul (0,0 %), on peut en conclure que le système est lié au processeur.

Bien que ces outils fonctionnent bien pour les systèmes autonomes, ils ne sont généralement pas conçus pour surveiller les environnements distribués volumineux. Pour surveiller les systèmes de production, des outils tels que Cloud Monitoring, Nagios, Prometheus et Sysdig peuvent fournir des analyses détaillées de la consommation des ressources par rapport à vos applications.

La surveillance des performances de votre application sur une période suffisante vous permet de collecter des données pour plusieurs métriques, telles que l'utilisation du processeur et de la mémoire, les E/S disques, les E/S réseau, les temps d'aller-retour, les latences, les taux d'erreur et le débit. Par exemple, les graphiques Cloud Monitoring suivants indiquent les niveaux d'utilisation et les charges du processeur ainsi que l'utilisation de la mémoire et du disque pour tous les serveurs exécutés dans un groupe d'instances géré Google Cloud. Pour en savoir plus sur cette configuration, consultez la présentation de l'agent Cloud Monitoring.

Charges du processeur, niveaux d'utilisation et utilisation de la mémoire et du disque pour tous les serveurs exécutés dans un groupe d'instances géré

Pour permettre l'analyse, la période de collecte des données doit être suffisamment longue pour montrer l'utilisation maximale et l'utilisation minimale des ressources. Vous pouvez ensuite analyser les données collectées afin de fournir un point de départ à la planification des capacités dans le nouvel environnement cible.

Mapper des ressources

Cette section explique comment établir le dimensionnement des ressources sur Google Cloud. Tout d'abord, vous devez effectuer une première évaluation du dimensionnement en fonction des niveaux existants de l'utilisation des ressources. Vous exécutez ensuite des tests d'analyse comparative des performances spécifiques à l'application.

Dimensionnement basé sur l'utilisation

Suivez ces étapes pour mapper le nombre de cœurs existant d'un serveur aux processeurs virtuels dans Google Cloud.

  1. Identifiez le nombre actuel de cœurs : reportez-vous à la commande lscpu dans la section précédente.

  2. Identifiez l'utilisation du processeur par le serveur : L'utilisation du processeur fait référence au temps que prend le processeur en mode utilisateur (%us) ou en mode noyau (%sy). Les processus nice (%ni) appartiennent également au mode utilisateur, tandis que les interruptions logicielles (%si) et les interruptions matérielles (%hi) sont gérées dans le mode noyau. Si le processeur n'effectue aucune de ces opérations, il est inactif ou attend la fin des E/S. Lorsqu'un processus attend la fin des E/S, il ne contribue pas aux cycles du processeur.

    Pour calculer l'utilisation actuelle du processeur d'un serveur, exécutez la commande top suivante :

    ...
    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'utilisation du processeur est définie comme suit :

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

    Vous pouvez également utiliser un outil de surveillance tel que Cloud Monitoring, qui peut recueillir l'utilisation et l'inventaire du processeur requis. Pour les déploiements d'applications sans autoscaling (c'est-à-dire exécutées avec un ou plusieurs nombres fixes de serveurs), nous vous recommandons d'utiliser l'utilisation maximale pour le dimensionnement du processeur. Cette approche protège les ressources de l'application contre les interruptions lorsque les charges de travail sont en utilisation maximale. Pour les déploiements en autoscaling (basés sur l'utilisation du processeur), l'utilisation moyenne du processeur constitue une référence sûre pour le dimensionnement. Dans ce cas, vous gérez les pics de trafic en effectuant un scaling horizontal du nombre de serveurs pendant toute la durée de ces pics.

  3. Allouez suffisamment de mémoire tampon pour gérer les pics : lorsque vous dimensionnez le processeur, incluez une mémoire tampon suffisante pour prendre en charge tout traitement non planifié susceptible de provoquer des pics inattendus. Par exemple, vous pouvez planifier une capacité de processeur telle que vous disposez d'une marge de 10 à 15 % supérieure à l'utilisation maximale prévue, et que l'utilisation maximale globale du processeur ne dépasse pas 70 %.

  4. Utilisez la formule suivante pour calculer le nombre de cœurs attendu sur GCP :

    Nombre de processeurs virtuels sur Google Cloud = 2 × PLAFOND[(nombre de cœurs × % d'utilisation) / (2 × % de seuil)]

    Ces valeurs sont définies comme suit :

    • nombre de cœurs : nombre de cœurs existant (calculé à l'étape 1)
    • % d'utilisation : utilisation du processeur par le serveur (calculée à l'étape 2)
    • % de seuil : utilisation maximale du processeur autorisée sur le serveur après prise en compte d'une marge suffisante (calculée à l'étape 3)

Prenons un exemple concret dans lequel vous devez mapper le nombre de cœurs d'un serveur physique Xeon E5640 à quatre cœurs s'exécutant sur site avec des processeurs virtuels dans Google Cloud. Les spécifications du serveur Xeon E5640 sont disponibles publiquement, mais vous pouvez également le vérifier en exécutant une commande telle que lscpu sur le système. Les chiffres se présentent comme suit :

  • Nombre de cœurs existant sur site = nombre de sockets (1) × nombre de cœurs (4) × nombre de threads par cœur (2) = 8.
  • Supposons que l'utilisation du processeur (% d'utilisation) observé pendant le pic de trafic soit de 40 %.
  • Vous avez prévu une marge de mémoire tampon supplémentaire de 30 %. Autrement dit, l'utilisation maximale du processeur (% de seuil) ne doit pas dépasser 70 %.
  • Nombre de processeurs virtuels sur Google Cloud = 2 × PLAFOND[(8 × 0,4) / (2 × 0,7)] = 6 processeurs virtuels
    (c'est-à-dire, 2 × PLAFOND[3,2 / 1,4] = 2 × PLAFOND[2,28] = 2 × 3 = 6)

Vous pouvez effectuer des évaluations semblables pour la RAM, le disque, les E/S réseau et d'autres ressources système.

Dimensionnement basé sur les performances

La section précédente a décrit en détail le mappage des processeurs physiques aux processeurs virtuels en fonction des niveaux d'utilisation du processeur actuels et attendus. Cette section examine l'application qui est exécutée sur le serveur.

Dans cette section, vous allez exécuter un ensemble standard et canonique de tests (analyses comparatives basées sur les programmes) afin de comparer les performances. En reprenant l'exemple décrit ci-dessus, supposons que vous exécutiez un serveur MySQL sur la machine Xeon E5. Dans ce cas, vous pouvez utiliser Sysbench OLTP pour comparer les performances de la base de données.

Un test en lecture-écriture simple sur MySQL à l'aide de Sysbench produit le résultat suivant :

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'exécution de cette analyse comparative vous permet de comparer les performances de votre environnement actuel et de Google Cloud en termes de nombre de transactions par seconde, de nombre total de lectures/écritures par seconde et de temps d'exécution de bout en bout. Nous vous recommandons d'exécuter plusieurs itérations de ces tests afin d'exclure toute anomalie. Pour observer les différences de performances en fonction de différents modèles de charge et de trafic, vous pouvez également répéter ces tests avec différents paramètres, tels que les niveaux de simultanéité, la durée des tests, le nombre d'utilisateurs simulés ou encore des taux d'apparition variables.

La comparaison des chiffres de performances de l'environnement actuel et de Google Cloud vous permettra de simplifier davantage votre évaluation initiale de la capacité. Si les tests d'analyse comparative effectués sur Google Cloud donnent des résultats semblables à ceux de l'environnement existant ou meilleurs que ceux-ci, vous pouvez ajuster davantage l'échelle des ressources en fonction des gains de performances. En revanche, si les analyses comparatives de votre environnement existant sont meilleures que celles de Google Cloud, procédez comme suit :

  • Revoyez l'évaluation initiale de la capacité.
  • Surveillez les ressources système.
  • Identifiez les zones de conflit possibles (par exemple, les goulots d'étranglement identifiés pour le processeur et la RAM).
  • Redimensionnez les ressources en conséquence.

Une fois que vous avez terminé, relancez les tests d'analyse comparative spécifiques à votre application.

Analyse comparative des performances de bout en bout

Jusqu'à présent, vous avez examiné un scénario simpliste ne comparant que les performances MySQL des solutions sur site et de Google Cloud. Dans cette section, vous allez examiner l'application distribuée à trois niveaux suivante.

Application distribuée à trois niveaux

Comme le montre le diagramme, vous avez probablement exécuté plusieurs analyses comparatives afin d'obtenir une évaluation raisonnable de votre environnement actuel et de Google Cloud. Toutefois, il peut être difficile de déterminer quel sous-ensemble d'analyses évalue le plus précisément les performances de votre application. En outre, il peut s'avérer fastidieux de gérer le processus de test, de la gestion des dépendances à l'installation des tests, jusqu'à l'exécution et l'agrégation des résultats dans différents environnements basés ou non sur le cloud. Dans de tels cas, vous pouvez utiliser PerfKitBenchmarker. PerfKit contient différents ensembles d'analyses comparatives permettant de mesurer et de comparer différentes offres sur plusieurs clouds. Il peut également exécuter certaines analyses comparatives sur site via des machines statiques.

Supposons que, pour l'application à trois niveaux du diagramme précédent, vous souhaitiez exécuter des tests pour comparer le temps de démarrage du cluster, le processeur et les performances réseau des VM sur Google Cloud. Grâce à PerfKitBenchmarker, vous pouvez exécuter plusieurs itérations de profils de test pertinents, qui produisent les résultats suivants :

  • Temps de démarrage du cluster : fournit une vue du temps de démarrage de la VM. Cela est particulièrement important si l'application est flexible et s'attend à ce que des instances soient ajoutées ou supprimées dans le cadre de l'autoscaling. Le graphique suivant montre que les temps de démarrage d'une instance Compute Engine n1-standard-4 restent relativement cohérents (jusqu'au 99e centile), entre 40 et 45 secondes.

    Temps de démarrage d'une instance Compute Engine n1-standard-4

  • Stress-ng : mesure et compare les performances exigeantes en calcul en mettant l'accent sur le processeur, le sous-système de mémoire et le compilateur d'un système. Dans l'exemple suivant, stress-ng exécute plusieurs tests de contrainte tels que bsearch, malloc, matrix, mergesort et zlib sur une instance Compute Engine n1-standard-4. Stress-ng mesure le débit des tests de contrainte en utilisant le nombre d'opérations factices (BogoMips) par seconde. Si l'on normalise les BogoMips sur différents résultats de tests de contrainte, on obtient le résultat suivant, qui indique la moyenne géométrique des opérations exécutées par seconde. Dans cet exemple, les BogoMips sont compris entre environ 8 000 par seconde au 50e centile et environ 10 000 par seconde au 95e centile. Notez que les BogoMips ne sont généralement utilisés que pour comparer les performances des processeurs autonomes. Ces opérations peuvent ne pas être représentatives de votre application.

    Moyenne géométrique des opérations exécutées par seconde

  • Netperf : mesure la latence grâce à des tests de requête et de réponse. Les tests de requête et de réponse s'exécutent au niveau de la couche d'application de la pile réseau. Cette méthode de test de latence implique toutes les couches de la pile. Elle est préférable aux tests ping pour mesurer la latence entre les VM. Le graphique suivant montre les latences de requête et de réponse TCP (TCP_RR) entre un client et un serveur qui s'exécutent dans la même zone Google Cloud. Les valeurs TCP_RR sont comprises entre environ 70 microsecondes au 50e centile et environ 130 microsecondes au 90e centile.

    Latences des requêtes et des réponses TCP entre un client et un serveur exécutés dans la même zone Google Cloud

Compte tenu de la nature de la charge de travail cible, vous pouvez exécuter d'autres profils de test à l'aide de PerfKit. Pour en savoir plus, consultez les analyses comparatives compatibles avec PerfKit.

Bonnes pratiques sur Google Cloud

Avant de configurer et d'exécuter un plan de migration sur Google Cloud, nous vous recommandons de suivre les bonnes pratiques de migration. Ces pratiques ne constituent qu'un point de départ. Vous devrez peut-être prendre en compte de nombreux autres aspects de votre application, tels que le découplage des dépendances, la tolérance aux pannes et le scaling à la hausse et à la baisse en fonction de la charge de travail des composants, ainsi que la façon dont chacun de ces aspects est mappé à Google Cloud.

  1. Identifiez les limites et les quotas de Google Cloud : avant de commencer formellement l'évaluation de la capacité, prenez connaissance des points importants à prendre en compte lors de la planification des ressources sur Google Cloud, par exemple :

    Répertoriez les composants d'Infrastructure as a Service (IaaS) et de Platform as a Service (PaaS) requis lors de la migration, et identifiez bien tous les quotas, toutes les limites et tous les ajustements disponibles pour chacun des services.

  2. Surveillez les ressources en continu : la surveillance continue des ressources peut vous permettre d'identifier les modèles et les tendances des performances du système et des applications. La surveillance permet non seulement d'établir des performances de base, mais également de démontrer la nécessité de mettre à niveau le matériel et de le faire revenir à des versions antérieures au fil du temps. Google Cloud propose différentes options pour déployer des solutions de surveillance de bout en bout :

  3. Dimensionnez correctement vos VM : identifiez les VM qui sont sous-provisionnées ou surprovisionnées. La configuration d'une surveillance de base, comme indiqué précédemment, devrait facilement vous apporter ces informations. Google Cloud fournit également des recommandations de dimensionnement basées sur l'historique d'utilisation d'une instance. En outre, en fonction de la nature de la charge de travail, si les types de machines prédéfinis ne répondent pas à vos besoins, vous pouvez créer une instance avec des paramètres de matériels virtualisés personnalisés.

  4. Utilisez les bons outils : pour les environnements à grande échelle, déployez des outils automatisés afin de minimiser les efforts manuels, par exemple :

Conclusions

La migration des ressources d'un environnement à un autre nécessite une planification minutieuse. Il est important de ne pas examiner les ressources matérielles de manière isolée, mais d'avoir une vision de votre application de bout en bout. Par exemple, au lieu de ne vous concentrer que sur la question de savoir si un processeur Sandy Bridge de 3.0 GHz sera deux fois plus rapide qu'un processeur Skylake de 1,5 GHz, concentrez-vous plutôt sur la façon dont les indicateurs clés de performance de votre application passent d'une plate-forme informatique à une autre.

Lorsque vous évaluez les exigences de mappage des ressources dans différents environnements, tenez compte des éléments suivants :

  • Les ressources système limitant votre application (par exemple le processeur, la mémoire, le disque ou le réseau)
  • L'impact de l'infrastructure sous-jacente (par exemple la génération du processeur, la vitesse d'horloge, HDD ou SSD) sur les performances de votre application
  • L'impact des choix de conception logicielle et architecturale (par exemple des charges de travail monothread ou multithread, des déploiements fixes ou en autoscaling) sur les performances de l'application
  • Les niveaux d'utilisation actuels et prévus des ressources de calcul, de stockage et de réseau
  • Les tests de performance les plus appropriés et représentatifs de votre application

La collecte de données par rapport à ces métriques via une surveillance continue vous permet de déterminer un plan de capacité initial. Vous pouvez ensuite effectuer une analyse comparative des performances afin d'affiner vos estimations de dimensionnement initiales.

Étape suivante