Aller au contenu

Stockage cloud : optimisez coût et performance

Mise à jour :

Quand on parle de performance des systèmes de stockage, on entend souvent le terme IOPS. Mais qu’est-ce que cela signifie vraiment ? Les IOPS (Input/Output Operations Per Second) désignent le nombre d’opérations d’entrée/sortie qu’un système de stockage peut effectuer en une seconde. En d’autres termes, c’est une mesure clé pour évaluer la rapidité d’accès aux données.

C’est quoi les IOPS ?

Les IOPS (Input/Output Operations Per Second) mesurent la capacité d’un système de stockage à traiter les opérations d’entrée/sortie en une seconde. On peut les calculer avec la formule suivante :

IOPS = 1 / (latence moyenne + temps de rotation + temps de transfert)

Chaque élément de la formule influence directement les IOPS. Voici une explication des termes.

  1. Latence moyenne : La latence moyenne correspond au temps qu’un système met pour démarrer une opération d’entrée/sortie. Elle inclut le délai pour accéder au disque et envoyer une réponse. Une latence faible améliore les
  2. Temps de rotation : Le temps de rotation s’applique aux disques mécaniques (HDD). C’est le temps nécessaire pour que les données se positionnent sous la tête de lecture.
  3. Temps de transfert : Le temps de transfert est le temps pour lire ou écrire les données une fois qu’elles sont accessibles. Il dépend de la vitesse du disque et de la taille des blocs.

La formule montre que pour augmenter les IOPS, il faut réduire la latence, le temps de rotation (pour les HDD) et le temps de transfert. C’est pourquoi les SSD et NVMe, qui ont des temps très faibles pour ces facteurs, offrent des performances bien supérieures aux HDD traditionnels.

Exemple de calcul - HDD vs SSD :

Prenons deux exemples pour illustrer le calcul théorique.

  • HDD 7 200 RPM :
    • Latence : 4 ms
    • Temps de rotation moyen : 4,17 ms
    • Temps de transfert pour 4 Ko : 0,005 ms
IOPS = 1 / (4 + 4,17 + 0,005) = 120 IOPS (environ)
  • SSD SATA :
    • Latence : 0,1 ms
    • Temps de rotation : 0 ms (pas de plateaux mécaniques)
    • Temps de transfert pour 4 Ko : 0,002 ms
IOPS = 1 / (0,1 + 0 + 0,002) = 9 900 IOPS (environ)

Comment mesurer les IOPS réels ?

Le calcul théorique des IOPS donne une estimation idéale des performances, mais pour connaître les IOPS réels de votre système, il faut effectuer des tests pratiques dans des conditions proches de l’environnement d’exploitation. Ces tests prennent en compte les charges de travail, les configurations matérielles et les contraintes logicielles.

Plusieurs outils sont disponibles pour évaluer les IOPS réels. Voici les plus courants :

  • dd (pour des tests simples, mais limités).
  • fio : L’un des outils les plus flexibles pour tester les performances des disques.

Mesure avec dd

Si vous souhaitez une méthode rapide et simple, utilisez la commande dd. Bien que moins précise, elle peut donner une idée des performances.

Terminal window
dd if=/dev/zero of=/tmp/testfile bs=4k count=100000 oflag=direct
100000+0 records in
100000+0 records out
409600000 bytes (410 MB, 391 MiB) copied, 3,94857 s, 104 MB/s
  • if=/dev/zero : Génère des données nulles pour l’écriture.
  • of=/tmp/testfile : Spécifie le fichier de sortie pour les tests d’écriture.
  • bs=4k : Définit la taille des blocs (4 Ko ici).
  • count=100000 : Nombre de blocs à écrire.
  • oflag=direct : Évite la mise en cache pour des résultats plus réalistes.

Le résultat indique le débit, mais vous pouvez estimer les IOPS en divisant le débit total par la taille des blocs.

Le résultat de votre commande dd montre les performances suivantes :

  • Nombre total d’opérations : 100 000 blocs de 4 Ko ont été écrits.
  • Taille totale transférée : 409 600 000 octets, soit environ 410 Mo.
  • Temps total : 3,94857 secondes.
  • Débit : 104 Mo/s.

Pour estimer les IOPS réels, on peut utiliser la formule suivante :

IOPS = (nombre de blocs transférés) / (temps total)

Ici, chaque bloc est de 4 Ko :

IOPS = 100 000 / 3,94857 ≈ 25 330 IOPS

La taille des blocs joue un rôle importants dans les IOPS et le débit global.

Voici comment cela impacte les performances :

  • Petits blocs (4 Ko, 8 Ko) : Augmentent le nombre d’opérations possibles, ce qui booste les IOPS, mais au prix d’une plus grande charge CPU.
  • Grands blocs (64 Ko, 128 Ko) : Réduisent les IOPS, mais augmentent le débit, idéal pour les transferts séquentiels de gros fichiers.

Vous pouvez tester avec dd différentes tailles de blocs pour voir l’impact sur vos résultats. Par exemple :

Terminal window
dd if=/dev/zero of=/tmp/testfile bs=64k count=10000 oflag=direct

Ce qui donne :

IOPS = 10 000 / 2,12744 ≈ 4 700 IOPS

Mesure avec fio

fio est un outil polyvalent qui permet de simuler des charges de travail et d’obtenir des statistiques détaillées sur les performances d’entrée/sortie.

Voici un exemple de commande pour mesurer les IOPS :

Terminal window
fio --name=test-iops --rw=randread --bs=4k --size=1G --numjobs=4 --iodepth=16 --runtime=30 --time_based
test-iops: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=16
...
fio-3.36
Starting 4 processes
test-iops: Laying out IO file (1 file / 1024MiB)
test-iops: Laying out IO file (1 file / 1024MiB)
test-iops: Laying out IO file (1 file / 1024MiB)
test-iops: Laying out IO file (1 file / 1024MiB)
fio: ENOSPC on laying out file, stopping
fio: pid=0, err=28/file:filesetup.c:240, func=write, error=No space left on device
note: both iodepth >= 1 and synchronous I/O engine are selected, queue depth will be capped at 1
note: both iodepth >= 1 and synchronous I/O engine are selected, queue depth will be capped at 1
note: both iodepth >= 1 and synchronous I/O engine are selected, queue depth will be capped at 1
Jobs: 3 (f=3): [r(3),X(1)][100.0%][r=124MiB/s][r=31.8k IOPS][eta 00m:00s]
test-iops: (groupid=0, jobs=1): err= 0: pid=2115941: Sat Dec 21 12:59:09 2024
read: IOPS=10.3k, BW=40.4MiB/s (42.3MB/s)(1212MiB/30001msec)
clat (usec): min=53, max=6852, avg=96.02, stdev=24.24
lat (usec): min=53, max=6852, avg=96.06, stdev=24.25
clat percentiles (usec):
| 1.00th=[ 78], 5.00th=[ 82], 10.00th=[ 85], 20.00th=[ 88],
| 30.00th=[ 90], 40.00th=[ 93], 50.00th=[ 97], 60.00th=[ 99],
| 70.00th=[ 100], 80.00th=[ 105], 90.00th=[ 108], 95.00th=[ 110],
| 99.00th=[ 120], 99.50th=[ 127], 99.90th=[ 172], 99.95th=[ 202],
| 99.99th=[ 693]
bw ( KiB/s): min=36936, max=43984, per=33.37%, avg=41377.81, stdev=1266.08, samples=59
iops : min= 9234, max=10996, avg=10344.34, stdev=316.56, samples=59
lat (usec) : 100=69.41%, 250=30.57%, 500=0.01%, 750=0.01%, 1000=0.01%
lat (msec) : 2=0.01%, 4=0.01%, 10=0.01%
cpu : usr=1.01%, sys=10.16%, ctx=310259, majf=0, minf=12
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=310155,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=16
test-iops: (groupid=0, jobs=1): err= 0: pid=2115942: Sat Dec 21 12:59:09 2024
read: IOPS=10.3k, BW=40.4MiB/s (42.3MB/s)(1211MiB/30001msec)
clat (usec): min=56, max=6832, avg=96.06, stdev=25.11
lat (usec): min=56, max=6832, avg=96.10, stdev=25.11
clat percentiles (usec):
| 1.00th=[ 79], 5.00th=[ 83], 10.00th=[ 85], 20.00th=[ 88],
| 30.00th=[ 90], 40.00th=[ 93], 50.00th=[ 97], 60.00th=[ 99],
| 70.00th=[ 100], 80.00th=[ 105], 90.00th=[ 108], 95.00th=[ 110],
| 99.00th=[ 120], 99.50th=[ 129], 99.90th=[ 178], 99.95th=[ 210],
| 99.99th=[ 676]
bw ( KiB/s): min=36792, max=43904, per=33.36%, avg=41367.68, stdev=1264.15, samples=59
iops : min= 9198, max=10976, avg=10341.81, stdev=316.09, samples=59
lat (usec) : 100=69.60%, 250=30.37%, 500=0.01%, 750=0.01%, 1000=0.01%
lat (msec) : 2=0.01%, 4=0.01%, 10=0.01%
cpu : usr=0.89%, sys=10.31%, ctx=310142, majf=0, minf=12
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=310007,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=16
test-iops: (groupid=0, jobs=1): err= 0: pid=2115943: Sat Dec 21 12:59:09 2024
read: IOPS=10.3k, BW=40.4MiB/s (42.3MB/s)(1211MiB/30001msec)
clat (usec): min=53, max=6871, avg=96.09, stdev=25.32
lat (usec): min=53, max=6871, avg=96.13, stdev=25.32
clat percentiles (usec):
| 1.00th=[ 78], 5.00th=[ 82], 10.00th=[ 85], 20.00th=[ 88],
| 30.00th=[ 90], 40.00th=[ 93], 50.00th=[ 97], 60.00th=[ 99],
| 70.00th=[ 100], 80.00th=[ 105], 90.00th=[ 108], 95.00th=[ 110],
| 99.00th=[ 121], 99.50th=[ 129], 99.90th=[ 178], 99.95th=[ 208],
| 99.99th=[ 693]
bw ( KiB/s): min=36984, max=43892, per=33.34%, avg=41351.41, stdev=1326.64, samples=59
iops : min= 9246, max=10973, avg=10337.75, stdev=331.68, samples=59
lat (usec) : 100=69.47%, 250=30.50%, 500=0.01%, 750=0.01%, 1000=0.01%
lat (msec) : 2=0.01%, 4=0.01%, 10=0.01%
cpu : usr=0.99%, sys=10.26%, ctx=310072, majf=0, minf=13
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=309946,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=16
Run status group 0 (all jobs):
READ: bw=121MiB/s (127MB/s), 40.4MiB/s-40.4MiB/s (42.3MB/s-42.3MB/s), io=3633MiB (3810MB), run=30001-30001msec
Disk stats (read/write):
dm-0: ios=927127/258, sectors=7417016/2696, merge=0/0, ticks=81383/56, in_queue=81439, util=100.00%, aggrios=930108/211, aggsectors=7440864/44848, aggrmerge=0/67, aggrticks=82838/158, aggrin_queue=83025, aggrutil=78.61%
sda: ios=930108/211, sectors=7440864/44848, merge=0/67, ticks=82838/158, in_queue=83025, util=78.61%

Analyse des résultats de votre test :

  1. IOPS moyens :
    • Chaque job réalise environ 10 341 à 10 344 IOPS pour des lectures aléatoires (blocs de 4 Ko).
    • Total des 4 jobs : 41 376 IOPS, une performance cohérente pour un SSD performant.
  2. Débit moyen :
    • Par job : 40,4 MiB/s (42,3 MB/s).
    • Total : 121 MiB/s (127 MB/s), bien optimisé pour les lectures aléatoires.
  3. Latence moyenne :
    • Moyenne : 96 µs, avec une faible variation.
    • ~69,5 % des opérations sont terminées en moins de 100 µs, ce qui montre une grande réactivité.
  4. Utilisation et observations
    • Profondeur de file d’attente : Malgré une configuration de 16, le moteur utilisé limite cette profondeur à 1, ce qui réduit le parallélisme et les IOPS.
    • Utilisation disque : 78,61 % de charge sur le disque principal, avec une petite marge pour augmenter la charge.
    • Erreur ENOSPC : Le test a échoué à créer des fichiers, probablement à cause d’un manque d’espace disponible ou de restrictions système.

Interprétation des résultats :

  • IOPS : Les 41 376 IOPS montrent une très bonne capacité pour des lectures aléatoires.
  • Latence : Avec 96 µs, le système répond très rapidement aux requêtes.
  • Débit : Le débit global est solide, mais des optimisations comme un meilleur moteur d’I/O ou des ajustements de profondeur de file pourraient améliorer les performances.

Optimisations possibles

  1. Changer le moteur d’I/O : Passez à un moteur d’I/O asynchrone, comme libaio, pour tirer parti d’une profondeur de file d’attente plus élevée et maximiser le parallélisme :

    Terminal window
    fio --name=test-iops --rw=randread --bs=4k --size=1G --numjobs=4 --iodepth=16 --ioengine=libaio --runtime=30 --time_based
  2. Résoudre l’erreur ENOSPC : Assurez-vous que le volume utilisé pour le test a suffisamment d’espace libre (au moins 4 Go pour les 4 jobs). Vérifiez également les permissions ou utilisez un autre chemin de fichier temporaire.

  3. Augmenter la taille des blocs : Si votre objectif est d’augmenter le débit plutôt que les IOPS, essayez des tailles de blocs plus grandes :

    Terminal window
    fio --name=test-iops --rw=randread --bs=64k --size=1G --numjobs=4 --iodepth=16 --runtime=30 --time_based
  4. Utiliser plus de jobs : Pour augmenter la charge sur le disque et maximiser les IOPS totaux, augmentez le nombre de jobs :

    Terminal window
    fio --name=test-iops --rw=randread --bs=4k --size=1G --numjobs=8 --iodepth=16 --runtime=30 --time_based
  5. Vérifier l’alignement des partitions : Un mauvais alignement des partitions peut limiter les performances, en particulier sur des SSD.

Qu’est-ce que le burst ?

Le burst est une fonctionnalité proposée par certains volumes de stockage dans le cloud qui permet de dépasser temporairement les performances normales (en termes de IOPS ou de débit). Cela s’avère particulièrement utile pour gérer des pics de charge ponctuels, lorsque les besoins en performance augmentent brièvement.

Lorsque les volumes ne sont pas utilisés à pleine capacité, ils accumulent des crédits de burst. Ces crédits s’accumulent avec le temps et peuvent être consommés lors de pics d’activité pour fournir des performances bien supérieures aux niveaux standards. Une fois ces crédits épuisés, le volume revient à ses performances normales, limitées à sa capacité de base.

Les avantages du burst

Le burst est particulièrement intéressant pour :

  • Gérer les pics de charge : Il permet de répondre à des demandes élevées sans devoir surdimensionner le stockage.
  • Optimiser les coûts : Les volumes avec burst sont généralement moins coûteux que ceux aux performances garanties.
  • Charges imprévisibles : Idéal pour des besoins fluctuant, comme les démarrages de systèmes ou des analyses ponctuelles.

Les limitations

Le burst a toutefois des contraintes :

  • Pas de performances élevées en continu : Une fois les crédits épuisés, les performances redescendent au niveau de base.
  • Surveillance nécessaire : Sans un suivi attentif, le risque de baisse soudaine de performance peut poser problème, surtout pour des applications critiques.

En résumé

Le burst est une solution idéale pour des charges de travail aux besoins irréguliers et pour gérer des pics courts. Cependant, pour des charges intensives et continues, il est préférable d’opter pour des volumes offrant des performances garanties, afin d’assurer une constance dans les traitements.

Les cas d’usage gourmands en IOPS

Les applications gourmandes en IOPS nécessitent une infrastructure de stockage capable de gérer un grand nombre d’opérations d’entrée/sortie par seconde. Ces scénarios, souvent critiques pour les entreprises, exigent une performance constante et fiable pour éviter les goulots d’étranglement qui peuvent affecter la productivité ou l’expérience utilisateur.

Bases de données transactionnelles

Les bases de données, comme les systèmes de gestion relationnels ou NoSQL, sont des exemples typiques d’applications gourmandes en IOPS :

  • Transactions intensives : Les applications de type OLTP (Online Transaction Processing), comme les systèmes bancaires, nécessitent des lectures et écritures rapides et fréquentes.
  • Accès aléatoire : La plupart des bases de données effectuent des opérations sur des blocs spécifiques, rendant les IOPS essentiels pour réduire la latence.
  • Exigences de cohérence : Les bases de données doivent garantir que les écritures sont synchrones pour éviter la corruption des données.

Big Data et analytique en temps réel

Les solutions de traitement Big Data nécessitent des capacités de stockage performantes pour répondre aux demandes massives de traitement et d’analyse :

  • Collecte de données : Les pipelines qui agrègent des millions d’événements par seconde nécessitent un stockage rapide pour ne pas créer de files d’attente.
  • Traitement analytique : Les moteurs comme Spark ou Hadoop bénéficient de IOPS élevés pour les tâches impliquant de gros volumes de données.
  • Tableaux de bord en temps réel : Les solutions d’analyse en temps réel (ex : surveillance d’infrastructure ou suivi de métriques d’application) dépendent d’un accès rapide aux données pour une visualisation instantanée.

Machines virtuelles et conteneurs

Les environnements virtualisés ou conteneurisés, souvent déployés à grande échelle, génèrent des charges de travail exigeantes pour les IOPS :

  • Machines virtuelles : Chaque VM a des besoins en IOPS pour ses propres opérations de lecture/écriture, et une mauvaise configuration peut entraîner une concurrence excessive sur le stockage partagé.
  • Conteneurs : Les orchestrateurs comme Kubernetes utilisent des volumes persistants pour stocker des données critiques, nécessitant des performances de stockage robustes.

Applications de streaming multimédia

Les plateformes de streaming vidéo ou audio génèrent un grand volume de lectures, notamment dans des scénarios où :

  • Demande simultanée élevée : Lorsqu’un grand nombre d’utilisateurs accèdent aux mêmes fichiers multimédias en simultané.
  • Caches et préchargements : Les serveurs de streaming utilisent souvent des caches pour réduire les lectures directes, mais nécessitent toujours des IOPS élevés pour gérer des fichiers volumineux.

Commerce en ligne et applications web

Les applications web et plateformes de commerce électronique reposent sur des IOPS élevés pour offrir une expérience utilisateur fluide :

  • Requêtes utilisateurs : Les recherches de produits, les consultations de pages, et les transactions créent une charge importante sur les bases de données.
  • Pic de trafic : Les événements comme le Black Friday nécessitent une montée en charge rapide pour éviter des ralentissements ou des interruptions.

Systèmes de sauvegarde et de restauration

Les sauvegardes régulières et les restaurations en cas de panne exigent des performances en IOPS pour réduire les temps d’inactivité :

  • Sauvegardes incrémentales : Nécessitent un grand nombre de lectures et écritures rapides pour ne pas perturber les systèmes en production.
  • Restauration rapide : Lorsqu’un système critique tombe en panne, des IOPS élevés garantissent une récupération rapide des données.

Les cas d’usage gourmands en IOPS couvrent un large éventail d’industries et d’applications critiques. Pour ces scénarios, une infrastructure bien configurée et capable de gérer un grand nombre d’opérations est essentielle pour garantir des performances fiables et éviter les interruptions. Planifier et surveiller ces charges de travail permet d’assurer un équilibre entre performance et coût.

Le choix des types et tailles de disques dans le cloud

Le type et la taille des disques dans le cloud influencent directement les performances (IOPS et débit) et les coûts. Voici comment faire les bons choix.

Types de disques

  • HDD : Pour les charges séquentielles et l’archivage, avec des IOPS faibles (~100-200).
  • SSD : Idéal pour des accès aléatoires rapides, offre des milliers d’IOPS.
  • NVMe : Le plus performant, pour des charges critiques avec des IOPS très élevés et une faible latence.

Pourquoi la taille influence les performances

Dans le cloud, les performances d’un disque sont souvent proportionnelles à sa taille :

  • IOPS proportionnels : Les fournisseurs lient le nombre d’IOPS à chaque Go alloué (ex. : 300 IOPS/100 Go). Un volume plus grand offre plus d’IOPS.
  • Débit maximal : Augmenter la taille augmente aussi le débit en Mo/s.

Critères de choix

  • Nature de la charge :
    • Transactionnelles : SSD ou NVMe.
    • Big Data : Disques à haut débit.
    • Archivage : HDD.
  • Optimisation des coûts :
    • Utilisez des volumes plus grands pour plus d’IOPS à moindre coût.
    • Préférez des disques provisionnés uniquement pour des besoins constants.

Adaptez vos choix de disque (type et taille) à vos besoins spécifiques. Une bonne planification garantit des performances optimales sans exploser votre budget cloud.

Conclusion

Les IOPS sont un indicateur clé pour évaluer les performances des systèmes de stockage. Comprendre leur fonctionnement et comment les mesurer est essentiel pour garantir des performances optimales, en particulier pour des charges de travail critiques. En choisissant les bons types et tailles de disques, vous pouvez optimiser vos coûts tout en offrant des performances fiables et évolutives.