Tests du disque OS éphémère NVMe

Je voulais vérifier un point : un disque OS éphémère (Ephemeral OS Disk) peut être placé sur Temp, NVMe ou Cache selon la série de votre VM. La documentation Microsoft indique que l’option de placement ne change pas la performance ni le coût de l’Ephemeral OS Disk, car la perf dépend du stockage local disponible sur le SKU.

Dans la vraie vie (et dans mes chiffres) : même si les trois restent “OS + éphémère”, le placement change le chemin I/O réel, et donc le comportement sous pression : la différence la plus visible n’est pas toujours l’IOPS moyen, mais la distribution de latence (p95/p99/p99.9) et la stabilité en charge soutenue.

Plusieurs articles ont déjà été écrits sur les performances de stockages Azure :

Et pour vous guider plus facilement dans cet article très (trop?) long, voici des liens rapides :

Mais avant d’aller directement dans les tests, prenons le temps de parcourir ensemble quelques notions concernant le stockage temporaire local attaché une machine virtuelle.

Qu’est-ce qu’un stockage temporaire local ?

Certaines tailles de machine virtuelle Azure incluent un stockage local temporaire éphémère, certaines des tailles les plus récentes utilisant des disques NVMe locaux temporaires.

Le stockage temporaire local utilise des disques supplémentaires approvisionnés directement en tant que stockage local sur un hôte de machine virtuelle Azure, plutôt que sur le stockage Azure distant. Ce type de stockage convient le mieux aux données qui n’ont pas besoin d’être conservées définitivement, telles que les caches, les mémoires tampons et les fichiers temporaires. 

Microsoft Learn

Le disque temporaire (souvent D: sous Windows) est un disque local éphémère classique : les données sont potentiellement perdues en si maintenance/redeploy/deallocate. Un disque OS éphémère peut être placé dessus (Temp placement, NVMe, ou sur le cache disk) selon le SKU de la machine virtuelle :

Étant donné que les données stockées sur ces disques ne sont pas sauvegardées, elles sont perdues lorsque la machine virtuelle est libérée ou supprimée. Le stockage éphémère est recréé au démarrage. Les disques éphémères locaux sont différents des disques de système d’exploitation éphémères.

Microsoft Learn

Qu’est-ce qu’un disque OS éphémère ?

Un disque OS éphémère est un disque système stocké localement sur l’hôte Azure, et non sur un stockage distant Azure Storage. Le point le plus important est que celui-ci est non persistant : en cas de redéploiement, de recréation, le disque OS éphémère revient toujours à l’image de départ.

Les disques de système d’exploitation éphémères sont créés sur le stockage local de la machine virtuelle (VM) et ne sont pas enregistrés dans le Stockage Azure à distance.

Microsoft Learn

Pourquoi utiliser un disque OS éphémère ?

Le premier avantage concerne le prix : On ne paye pas le volume de stockage du disque éphémère. Celui-ci est intégré au prix de la machine virtuelle. De plus, les performances sont bien meilleures que la plupart des disques :

Les disques OS éphémères conviennent parfaitement aux charges de travail sans état, dans lesquelles les applications tolèrent les pannes de machines virtuelles individuelles tout en restant sensibles aux délais de mise en service ou à la réimagerie d’instances spécifiques.

Comparé à un disque de système d’exploitation standard, un disque éphémère offre une latence plus faible pour les opérations de lecture/écriture et permet une réinitialisation plus rapide des machines virtuelles.

Microsoft Learn

Pourquoi ne pas utiliser un disque OS éphémère ?

Comme annoncé plus haut, le disque OS éphémère ne doit pas contenir de la donnée critique. De plus, des fonctionnalités basiques ne sont pas disponibles :

  • Arrêt / Démarrage de la VM
  • Capture d’image VM
  • Captures instantanées de disque
  • Azure Disk Encryption
  • Échanges de disques système d’exploitation

Sur le portail Azure, certains menus sont tout simplement grisés pour ce type de VM :

Les fonctionnalités de sauvegarde et de reprise d’activité après sinistres sont elles aussi désactivés :

Comment savoir si le SKU de ma VM dispose d’un stockage temporaire local ?

La doc détaille trois placements possibles selon les VM :

  • NVMe Disk Placement (GA sur des séries récentes v6+)
  • Temp Disk / Resource Disk Placement
  • Cache Disk Placement

La nature et le volume du stockage temporaire local dépend en effet de la famille et du SKU de votre machine virtuelle :

Attention, certaines machines virtuelles n’ont tout simplement pas de stockage temporaire local :

Quid de la SLA d’une VM avec un disque OS éphémère ?

Le base disk influence l’engagement contractuel et certaines phases de provisioning, mais il ne modifie pas le chemin I/O steady-state de l’OS.

Depuis peu, Azure permet de choisir le type de “base disk” associé à un disque OS éphémère : Standard HDD, Standard SSD ou Premium SSD.

Attention cependant, ce “base disk” ne correspond pas au support physique sur lequel l’OS s’exécute.

Dans le cas d’un disque OS éphémère, le système fonctionne toujours sur le stockage local de l’hôte (NVMe / Temp / Cache selon le placement). Le type de base disk désigne le type de disque managé logique utilisé par Azure lors du provisioning et pour l’engagement contractuel.

La prise en charge SSD est une nouvelle option qui permet aux clients de choisir le type de disque principal utilisé pour le disque d’OS éphémère. Auparavant, le disque de base ne pouvait être qu’un HDD standard. À présent, les clients peuvent choisir entre les trois types de disques : HDD Standard (Standard_LRS), SSD Standard (StandardSSD_LRS) ou SSD Premium (Premium_LRS). En utilisant SSD avec disque de système d’exploitation éphémère, les clients peuvent bénéficier des améliorations suivantes :

  • Contrat SLA amélioré : les machines virtuelles créées avec SSD Premium fournissent un contrat SLA supérieur à celui des machines virtuelles créées avec hDD Standard. Les clients peuvent améliorer le contrat SLA pour leurs machines virtuelles éphémères en choisissant SSD Premium comme disque de base.

Microsoft Learn

Concrètement :

  • Le choix du base disk peut améliorer la SLA contractuelle de la VM.
  • Il peut également influer sur certaines phases spécifiques (provisioning, re-imaging, lectures liées au backing managed disk).
  • En revanche, il ne modifie pas les performances steady-state du stockage local sur lequel tourne réellement l’OS.

Autrement dit :

Choisir Premium SSD comme base disk améliore la SLA et certains scénarios liés au provisioning,
mais ne transforme pas un placement NVMe ou Temp en Premium SSD local.

Pourcentage de disponibilité (SSD Premium, SSD Premium v2 et Ultra Disk)Pourcentage de disponibilité (disque géré SSD standard)Pourcentage de disponibilité (disque géré HDD standard)Avoir Service
< 99,9 %< 99,5 %< 95 %10 %
< 99 %< 95 %< 92 %25 %
< 95 %< 90 %< 90 %100 %

Quid des performances d’une VM avec un disque OS éphémère ?

Les disques temporaires locaux ne sont pas comptabilisés par rapport aux IOPS et aux limites de débit de la machine virtuelle. De plus, Microsoft nous indique que les performances du disque OS éphémère dépendent de la machine et non du type de stockage local :

Le disque OS éphémère exploite le stockage local intégré à la machine virtuelle. Étant donné que différentes machines virtuelles ont différents types de stockage local (disque de cache, disque temporaire et disque NVMe), l’option de placement définit l’emplacement où le disque de système d’exploitation éphémère est stocké. Le choix du placement n’influence ni les performances ni le coût du disque OS éphémère. Ses performances reposent sur le stockage local de la machine virtuelle. Selon le type de machine virtuelle, trois modes de placement sont proposés.

  • Placement de disque NVMe (généralement disponible) : le type de placement de disque NVMe est désormais en disponibilité générale (GA) sur la dernière série de machines virtuelles v6 de la dernière génération, comme Dadsv6, Ddsv6, Dpdsv6, etc.
  • Placement de disque temporaire (également appelé Placement de disque de ressources) : le type de placement de disque temporaire est disponible sur les machines virtuelles avec un disque temp comme Dadsv5, Ddsv5, etc.
  • Emplacement du disque de cache : le type de placement du disque de cache est disponible sur les anciennes machines virtuelles qui avaient un disque de cache tel que Dsv2, Dsv3, etc.

Microsoft Learn

La performance théorique dépend du SKU, pas du placement. En revanche, comme chaque placement repose sur un support physique différent (NVMe, temp disk, cache disk), le comportement réel sous charge peut varier sensiblement.

Mais cette seconde partie de la documentation Microsoft m’intrigue quand même :

Amélioration des performances : en choisissant SSD Premium comme disque de base, les clients peuvent améliorer les performances de lecture du disque de leurs machines virtuelles. Bien que la plupart des écritures se produisent sur le disque temporaire local, certaines lectures sont effectuées à partir de disques managés. Les disques SSD Premium fournissent 8 à 10 fois plus d’IOPS que hDD Standard.

Microsoft Learn

J’ai créé plusieurs machines virtuelles avec le SKU Standard_D32ads_v7, dont voici les performances pour le stockage local :

Pourtant, les deux différents type de disque OS éphémère créés indiquent exactement les mêmes performances sur le portail Azure :

En extrapolant naïvement à partir de la capacité totale locale (440 Go x4), j’aurais pu m’attendre qu’en faisant un produit en croix basé sur la taille totale des 4 disques locaux attachés à ma VM, je m’attendais à trouver les performances suivantes sur mon disque OS éphémère :

  • IOPS max : 43296 IOPS
  • Bande passante max : 323 Mo/sec

Passons maintenant à l’approche utilisée pour mes tests.

Protocole de test que j’ai déployé :

  • Machines virtuelles Azure :

Pour éviter toute ambiguïté, les 4 VMs utilisent toutes un disque OS avec Windows Server 2022, mais sur des placements différents :

Nom de VMSKUType de disque OS
perftempStandard_D32ads_v5Ephemeral OS Disk – Temp placement
perfnvme-vmStandard_D32ads_v7Ephemeral OS Disk – NVMe placement
perfcacheStandard_D32ds_v4Ephemeral OS Disk – Cache placement
perfssdStandard_D32ads_v7OS Disk Premium SSD (référence)
  • Outils de mesure :

Plusieurs outils de mesures ont été utilisés afin de mieux comprendre les performances :

Nom de l’outilMesures effectuéesURL de téléchargement
fioIOPS (read/write), bande passante (MB/s), latence moyenne, percentiles (p95, p99), tests steady-state, profils personnalisés (4K, 64K, queue depth, etc.)https://github.com/axboe/fio
CrystalDiskMarkIOPS séquentiel et aléatoire, débit (MB/s), tests QD1/QD32, 4K/8K/1Mhttps://crystalmark.info/en/software/crystaldiskmark/
AS SSD BenchmarkIOPS 4K read/write, latence d’accès, score global (read/write/total), test copie (ISO, Program, Game), test incompressiblehttps://www.alex-is.de/PHP/fusion/downloads.php?cat_id=4

CrystalDiskMark – Smoke Test :

L’outil a été laissé dans sa configuration de base. Cela permet de provoquer :

  • Meilleur profit des caches (OS, contrôleur, stockage local, cache host)
  • Meilleur visu du burst (très bon pendant un court moment)
  • Ne force pas steady-state

Comme attendu, cela donne des chiffres parfois “spectaculaires”, notamment en lecture. Et c’est exactement le biais évoqué plus haut qui en ressort :

  • Tests courts
  • Pas de warm-up réel
  • Influence potentielle du cache

CrystalDiskMark confirme les tendances générales, mais ne permet pas de juger la stabilité sous charge soutenue.

AS SSD Benchmark – Latence & Incompressible :

AS SSD Benchmark va un peu plus loin que CrystalDiskMark et donne d’autres infos : Seq / 4K / 4K-64Thrd + “Acc.time”. Cela donne dans les résultats une meilleure visibilité des différences d’écriture, parfois très forts selon le disque.

AS SSD est connu pour être très sensible à :

  • la façon dont le chemin I/O gère les écritures (flush, cache, barrières)
  • la latence (et il la met en avant via “Acc.time”)
  • et la façon dont le driver/stack de stockage réagit

AS SSD peut donc apparaître comme plus sévère que CrystalDiskMark sur les écritures quand il tombe sur un scénario où le stockage/driver applique davantage de contraintes (flush/ordering).

Les tests faits via AS SSD nous apporte donc ici deux éléments intéressants :

  • Mesure directe de latence d’accès
  • Test incompressible (moins biaisé par cache/compression)

Dans notre cas, on peut donc en déduire que disque éphémère NVMe domine clairement en latence pure, que le disque éphémère temporaire reste très proche, que le disque éphémère cache montre une latence un peu plus élevée, et que le disque Premium SSD affiche la latence la plus importante.

Le score global reflète davantage l’expérience “ressentie” qu’un simple IOPS max.

fio – tests soutenus proches d’un workload :

Contrairement à CrystalDiskMark (smoke test court) et AS SSD (latence & incompressible), fio permet de :

  • contrôler précisément le pattern I/O
  • imposer une durée suffisante
  • forcer le bypass du cache OS (–direct=1)
  • introduire une phase de warm-up
  • mesurer les percentiles élevés (p95, p99, p99.9)

Autrement dit, fio mesure le comportement soutenu proche d’un workload réel.

Je suis passé par Chocolatey pour installer fio sur mes 4 machines virtuelles Azure grâce au script PowerShell suivant :

Set-ExecutionPolicy Bypass -Scope Process -Force

[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

choco --version

choco install fio -y

fio --version

J’ai ensuite lancé le script fio suivant sur chacun des machines virtuelles pour générer et centraliser mes résultats sur un Azure file share. Dans ce script, fio teste :

  • Random 4K en montée de charge (sweep de queue depth QD1→64) en lecture/écriture
  • Un “peak” comparable : random 4K QD32, 8 jobs (lecture + écriture).
  • Un run plus long “steady-state” : random write 4K QD32, 8 jobs (soutenu).
  • Le coût de la durabilité/synchronisation : random write 4K QD1, 1 job, fsync=1.
  • Le débit séquentiel : read/write 1M, QD32, 4 jobs.
  • Et il fait un warmup au début.
# =========================
# FIO -> Z:\fio-results\ (NO subfolders)
# VM name only in OUTPUT (filename + header), not in folder structure
# Tests:
#  - Scaling (QD sweep) : randread4k / randwrite4k (for graphs, not for "max" headline)
#  - Peak controlled    : randread4k / randwrite4k @ QD32 NJ8 (reference "max comparable")
#  - Steady-state       : randwrite4k @ QD32 NJ8 (longer run)
#  - Sync durability    : randwrite4k QD1 NJ1 fsync=1
#  - Throughput         : seq read/write 1m @ QD32 NJ4
#
# Notes:
# - Uses --direct=1 (bypass OS cache)
# - Uses time_based + ramp_time (warm-up)
# - Emits a CSV summary you can aggregate across VMs
# =========================

param(
  [string]$OutDir   = "Z:\fio-results",
  [string]$Target   = "C:\fio_test.dat",   
  [string]$FileSize = "32G",               # Bigger => fewer cache illusions
  [int]   $Runtime  = 60,
  [int]   $RampTime = 10,
  [string]$FioExe   = "fio"                # Or full path: C:\fio\fio.exe
)

$VmName = $env:COMPUTERNAME

function Ensure-Dir {
  param([string]$Path)
  try {
    New-Item -ItemType Directory -Path $Path -Force | Out-Null
    return $true
  } catch {
    return $false
  }
}

# Prefer Z:\fio-results, fallback to C:\fio-results if Z: not available
if (-not (Ensure-Dir -Path $OutDir)) {
  $OutDir = "C:\fio-results"
  if (-not (Ensure-Dir -Path $OutDir)) {
    Write-Host "ERROR: Unable to create output directory (Z:\fio-results or C:\fio-results)." -ForegroundColor Red
    exit 1
  }
}

# Ensure fio exists
try { & $FioExe --version | Out-Null } catch {
  Write-Host "ERROR: fio not found. Put fio.exe in PATH or set -FioExe to its full path." -ForegroundColor Red
  exit 1
}

function Run-FioTest {
  param(
    [Parameter(Mandatory=$true)][string]$TestName,
    [Parameter(Mandatory=$true)][string]$TestType,
    [Parameter(Mandatory=$true)][string[]]$Args
  )

  $ts = Get-Date -Format "yyyyMMdd-HHmmss"
  $outFile = Join-Path $OutDir "$($VmName)_$($TestName)_$ts.txt"

  @(
    "VM: $VmName"
    "Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
    "TestType: $TestType"
    "Test: $TestName"
    "Command: $FioExe $($Args -join ' ')"
    "----------------------------------------"
  ) | Out-File -FilePath $outFile -Encoding utf8

  & $FioExe @Args 2>&1 | Out-File -FilePath $outFile -Append -Encoding utf8
  return $outFile
}

function Parse-FioSummary {
  param(
    [Parameter(Mandatory=$true)][string]$FilePath,
    [Parameter(Mandatory=$true)][string]$TestType
  )

  $content = Get-Content $FilePath -Raw

  $readLine  = [regex]::Match($content, '^\s*read:\s*IOPS=([0-9\.]+[kKmM]?),\s*BW=([0-9\.]+[A-Za-z\/]+)', 'Multiline')
  $writeLine = [regex]::Match($content, '^\s*write:\s*IOPS=([0-9\.]+[kKmM]?),\s*BW=([0-9\.]+[A-Za-z\/]+)', 'Multiline')

  # fio prints percentiles when --percentile_list is used
    $p50  = [regex]::Match($content, '50\.00th=\[\s*([0-9]+)\]', 'Multiline')
    $p95  = [regex]::Match($content, '95\.00th=\[\s*([0-9]+)\]', 'Multiline')
    $p99  = [regex]::Match($content, '99\.00th=\[\s*([0-9]+)\]', 'Multiline')
    $p999 = [regex]::Match($content, '99\.90th=\[\s*([0-9]+)\]', 'Multiline')


  [PSCustomObject]@{
    VM         = $VmName
    TestType   = $TestType
    File       = Split-Path $FilePath -Leaf
    ReadIOPS   = if ($readLine.Success)  { $readLine.Groups[1].Value } else { "" }
    ReadBW     = if ($readLine.Success)  { $readLine.Groups[2].Value } else { "" }
    WriteIOPS  = if ($writeLine.Success) { $writeLine.Groups[1].Value } else { "" }
    WriteBW    = if ($writeLine.Success) { $writeLine.Groups[2].Value } else { "" }
    P50_usec   = if ($p50.Success)  { $p50.Groups[1].Value } else { "" }
    P95_usec   = if ($p95.Success)  { $p95.Groups[1].Value } else { "" }
    P99_usec   = if ($p99.Success)  { $p99.Groups[1].Value } else { "" }
    P999_usec  = if ($p999.Success) { $p999.Groups[1].Value } else { "" }
  }
}

# Common args (cache-light, more comparable)
$common = @(
  "--filename=$Target",
  "--size=$FileSize",
  "--direct=1",
  "--ioengine=windowsaio",
  "--runtime=$Runtime",
  "--ramp_time=$RampTime",
  "--time_based",
  "--group_reporting",
  "--thread",
  "--percentile_list=50:95:99:99.9"
)

$tests = @()

# ------------------------------------------------------------
# 0) Optional preconditioning (light warm-up) for consistency
# ------------------------------------------------------------
$tests += @{
  Type="warmup"
  Name="warmup_write1m_qd8_nj1_30s"
  Args=@(
    "--name=warmup",
    "--filename=$Target",
    "--size=$FileSize",
    "--direct=1",
    "--ioengine=windowsaio",
    "--bs=1m",
    "--iodepth=8",
    "--numjobs=1",
    "--rw=write",
    "--runtime=30",
    "--ramp_time=0",
    "--time_based",
    "--group_reporting",
    "--thread"
  )
}

# ------------------------------------------------------------
# 1) Scaling (QD sweep) - for graphs only
#    Keep it longer than micro-runs to reduce burst artifacts
# ------------------------------------------------------------
foreach ($qd in @(1,2,4,8,16,32,64)) {
  $tests += @{
    Type="scaling"
    Name="scaling_randread4k_qd$qd_nj8_90s"
    Args=@(
      "--name=rr_qd$qd",
      "--filename=$Target",
      "--size=$FileSize",
      "--direct=1",
      "--ioengine=windowsaio",
      "--bs=4k",
      "--iodepth=$qd",
      "--numjobs=8",
      "--rw=randread",
      "--runtime=90",
      "--ramp_time=15",
      "--time_based",
      "--group_reporting",
      "--thread",
      "--percentile_list=50:95:99:99.9"
    )
  }

  $tests += @{
    Type="scaling"
    Name="scaling_randwrite4k_qd$qd_nj8_90s"
    Args=@(
      "--name=rw_qd$qd",
      "--filename=$Target",
      "--size=$FileSize",
      "--direct=1",
      "--ioengine=windowsaio",
      "--bs=4k",
      "--iodepth=$qd",
      "--numjobs=8",
      "--rw=randwrite",
      "--runtime=90",
      "--ramp_time=15",
      "--time_based",
      "--group_reporting",
      "--thread",
      "--percentile_list=50:95:99:99.9"
    )
  }
}

# ------------------------------------------------------------
# 2) Peak controlled (reference values, comparable across disks)
# ------------------------------------------------------------
$tests += @{
  Type="peak"
  Name="peak_randread4k_qd32_nj8_120s"
  Args=@(
    "--name=peak_rr",
    "--filename=$Target",
    "--size=$FileSize",
    "--direct=1",
    "--ioengine=windowsaio",
    "--bs=4k",
    "--iodepth=32",
    "--numjobs=8",
    "--rw=randread",
    "--runtime=120",
    "--ramp_time=20",
    "--time_based",
    "--group_reporting",
    "--thread",
    "--percentile_list=50:95:99:99.9"
  )
}

$tests += @{
  Type="peak"
  Name="peak_randwrite4k_qd32_nj8_120s"
  Args=@(
    "--name=peak_rw",
    "--filename=$Target",
    "--size=$FileSize",
    "--direct=1",
    "--ioengine=windowsaio",
    "--bs=4k",
    "--iodepth=32",
    "--numjobs=8",
    "--rw=randwrite",
    "--runtime=120",
    "--ramp_time=20",
    "--time_based",
    "--group_reporting",
    "--thread",
    "--percentile_list=50:95:99:99.9"
  )
}

# ------------------------------------------------------------
# 3) Steady-state style (longer, to see sustained behavior)
# ------------------------------------------------------------
$tests += @{
  Type="steady"
  Name="steady_randwrite4k_qd32_nj8_180s"
  Args=@(
    "--name=steady_rw",
    "--filename=$Target",
    "--size=$FileSize",
    "--direct=1",
    "--ioengine=windowsaio",
    "--bs=4k",
    "--iodepth=32",
    "--numjobs=8",
    "--rw=randwrite",
    "--runtime=180",
    "--ramp_time=30",
    "--time_based",
    "--group_reporting",
    "--thread",
    "--percentile_list=50:95:99:99.9"
  )
}

# ------------------------------------------------------------
# 4) Sync durability penalty (OS-like durability semantics)
# ------------------------------------------------------------
$tests += @{
  Type="sync"
  Name="sync_randwrite4k_qd1_nj1_fsync1_60s"
  Args= $common + @(
    "--name=sync_rw",
    "--bs=4k",
    "--iodepth=1",
    "--numjobs=1",
    "--rw=randwrite",
    "--fsync=1"
  )
}

# ------------------------------------------------------------
# 5) Throughput (large blocks)
# ------------------------------------------------------------
$tests += @{
  Type="throughput"
  Name="seqread1m_qd32_nj4_60s"
  Args= $common + @(
    "--name=sr_1m",
    "--bs=1m",
    "--iodepth=32",
    "--numjobs=4",
    "--rw=read"
  )
}

$tests += @{
  Type="throughput"
  Name="seqwrite1m_qd32_nj4_60s"
  Args= $common + @(
    "--name=sw_1m",
    "--bs=1m",
    "--iodepth=32",
    "--numjobs=4",
    "--rw=write"
  )
}

# ------------------------------------------------------------
# Run + summary
# ------------------------------------------------------------
$results = @()

foreach ($t in $tests) {
  Write-Host "Running $($t.Type) / $($t.Name) ..." -ForegroundColor Cyan
  $file = Run-FioTest -TestName $t.Name -TestType $t.Type -Args $t.Args
  $results += Parse-FioSummary -FilePath $file -TestType $t.Type
}

$ts = Get-Date -Format "yyyyMMdd-HHmmss"
$summaryCsv = Join-Path $OutDir "fio_summary_$($VmName)_$ts.csv"
$summaryTxt = Join-Path $OutDir "fio_summary_$($VmName)_$ts.txt"

$results | Export-Csv -NoTypeInformation -Path $summaryCsv -Encoding UTF8
$results | Sort-Object TestType, File | Format-Table -AutoSize | Out-String | Out-File -FilePath $summaryTxt -Encoding utf8

Write-Host "Done. Outputs in: $OutDir" -ForegroundColor Green
Write-Host "Summary CSV: $summaryCsv" -ForegroundColor Green
Write-Host "Summary TXT: $summaryTxt" -ForegroundColor Green

Synthèse des résultats :

Cela nous donne les synthèses suivantes :

DiskPeak 4K ReadPeak 4K WriteSteady 4K WriteSeq ReadSeq WriteSync 4K Write
Temp (D32ads_v5)153k153k153k1951 MiB/s1950 MiB/s9.3k
Cache (D32ds_v4)98k93k94k1888 MiB/s1888 MiB/s7.9k
NVMe (D32ads_v7)146k60k60k1071 MiB/s536 MiB/s7.6k
Premium SSD10k4k3k152 MiB/s127 MiB/s507
DiskIOPSP50 (µs)P95 (µs)P99 (µs)P99.9 (µs)
Temp (D32ads_v5)153k212381523903
Cache (D32ds_v4)93k2694526281104
NVMe (D32ads_v7)60k2614376011048
Premium SSD4k40276110891827

Ce que peut en dire de ces tests :

Sur Temp, Cache et NVMe, on peut lire que Peak ≈ Steady. Cela signifie que :

  • Pas de burst artificiel
  • Pas d’effet cache court terme
  • Pas de chute après 30 secondes
  • Pas d’effondrement après warm-up

Le comportement observé est soutenu, et c’est extrêmement important, car beaucoup de benchmarks “rapides” montrent un pic initial qui s’effondre après 1 à 2 minutes.
Ici, ce n’est pas le cas.

  • NVMe vs Temp : contre-intuitif

Intuitivement, on pourrait penser que NVMe est supérieur à Temp. Or, en écriture 4K soutenue :

  • Temp : 153k IOPS
  • NVMe : 60k IOPS

Ce n’est pas un artefact. De plus : Peak = Steady sur NVMe Cela indique un plafond structurel, pas un effet transitoire. La performance dépend donc du chemin I/O exposé par le SKU, pas uniquement de la nature “NVMe” du support. C’est un point fondamental.

  • Premium SSD : changement de catégorie

Enfin, nous sommes dans un monde différent avec le premium ssd, En 4K write steady, le Premium SSD monte à 2 926 IOPS, avec un pique à 3500 IOPS. On n’est plus dans la même catégorie. Le disque managé respecte son cap IOPS contractuel :

Ce test montre très clairement la différence entre un stockage managé distant avec limite provisionnée et stockage local intégré au SKU.

Si un stockage persistant est nécessaire, à vous maintenant de voir quel disque correspondra mieux à vos besoins :

  • Pourquoi regarder p99/p99.9 et pas juste les IOPS ?

Microsoft documente les notions de limites cached/uncached et le fait qu’un workload peut être IO capped. Quand cela arrive :

  • Les IOPS plafonnent
  • La file d’attente sature
  • La latence augmente

Ton plateau write NVMe en 4K random (QD sweep) a exactement la signature d’une limite plateforme. Deux disques peuvent faire 100k IOPS :

  • L’un avec P99.9 à 10 ms
  • L’autre avec P99.9 à 50+ ms

Ils n’auront pas du tout la même sensation côté OS. Le P99.9 capture les moments où :

  • la queue est saturée
  • un flush bloque
  • un throttling intervient

C’est ce qui compte en production.

  • Comment le cache d’Azure nous trompe ?

Microsoft indique qu’un disque avec host caching peut temporairement dépasser la limite disque. Cela explique pourquoi :

  • CrystalDiskMark peut afficher des chiffres “incroyables”
  • Un bench court peut mesurer le cache plutôt que le support réel

Si un benchmark va “trop vite”, c’est souvent un cache. De plus :

  • Microsoft recommande un warm-up
  • Les cached reads atteignent leurs meilleurs chiffres après stabilisation

Le cache modifie donc la mesure. En write, ce n’est pas magique :

Quand le caching est en Read/Write, l’écriture doit être validée dans le cache et sur le disque.
Elle compte dans les limites cached et uncached. Le cache ne supprime pas la limite soutenue.

  • Pourquoi certains outils de mesure peuvent être trompeur lors de tests sur Azure ?

De ce fait, certains outils comme CrystalDiskMark, sont très bien pour un smoke test, mais :

  • Les durées courtes,
  • Les patterns,
  • et l’absence de phase de warm-up

font qu’ils mesurent souvent le cache, pas le support réel. Un chiffre « trop beau » est souvent… un cache.

  • La limite n’est pas le disque. C’est la VM :
VMvCPUPeak 4K ReadPeak 4K WriteSteady 4K WriteP99 Write (µs)P99.9 Write (µs)
D32ads_v732~146k~60k~60k~601~1048
D64ads_v764~291k~120k~120k~580~1010
VMSeq ReadSeq Write
D32ads_v7~1071 MiB/s~536 MiB/s
D64ads_v7~2144 MiB/s~1067 MiB/s

Ces nouveaux tests montrent un comportement très clair :

  • NVMe en D32 plafonne à ~60k IOPS write
  • Le même NVMe en D64 monte à ~120k IOPS
  • La latence reste comparable

Le support physique n’a pas changé. Le workload n’a pas changé. Le placement n’a pas changé.Ce qui a changé : le SKU, cela démontre que Le plafond de performance est imposé par la capacité I/O exposée par la VM, pas par le média NVMe lui-même.

Autrement dit, le NVMe ne “donne” pas 60k IOPS, la VM D32 expose 60k IOPS.

Mais attention, les chiffres donnés dans la documentation Microsoft décrivent le potentiel maximal du stockage local temporaire de la VM (souvent agrégé sur plusieurs disques). Un disque OS éphémère ‘NVMe placement’ n’est pas automatiquement équivalent à ce chemin I/O, et un test ‘fichier’ ajoute un overhead. On compare donc des plafonds de nature différente.

  • Pourquoi les tests “fsync=1” ne prouvent pas la durabilité ?

fsync=1 mesure le coût d’un flush côté OS, mais ne prouve pas la persistance réelle sur le média ou la résistance à un crash hôte. fio indique qu’en non-buffered I/O, il peut ne pas sync comme attendu :

  • fsync=1 force un flush côté OS
  • mais ça ne valide pas une persistance réelle côté hyperviseur / host
  • ce n’est pas un test de crash-consistency

Donc si tu veux un “durability test”, il faut une variante (ex : buffered ou job dédié) et mesurer la phase sync séparément.

Conclusion

Si je résume :

  • Les trois disques OS éphémères surpassent le Premium SSD managé
  • NVMe offre une latence très stable et évolue fortement avec le SKU
  • Temp placement reste le plus performant en écriture 4K soutenue dans ce test précis
  • Cache dépend davantage du comportement de file d’attente

Mais surtout, Microsoft a raison : la performance dépend du stockage local. Mais ce que la documentation ne met pas en avant, c’est que le stockage local n’est pas homogène selon le placement. Et c’est là que tout se joue :

  • Les différences ne sont pas toujours visibles sur l’IOPS moyen. Elles apparaissent dans les percentiles élevés (p99/p99.9)
  • C’est exactement ce que Microsoft ne détaille pas explicitement : la performance dépend du stockage local… mais le stockage local n’a pas la même nature physique selon le placement

D’un point de vue technique :

  1. Le placement ne change pas le coût
  2. Le placement ne change pas la “promesse marketing”
  3. Mais le placement change le chemin I/O réel

Et donc, en fonction de la charge de travail :

  • Pour une charge de travail sensible à la latence (SQL temporaire, build intensif, traitement parallèle), le NVMe placement est clairement le plus intéressant.
  • Pour des workloads stateless classiques, Temp reste un excellent compromis.
  • Le Cache placement, sur des générations plus anciennes, reste viable mais moins moderne.
  • Enfin, un Premium SSD managé reste plus simple opérationnellement, mais il est largement dépassé en performance pure par le stockage local éphémère.

Machine virtuelle : changez de taille !

Il arrive qu’une machine virtuelle ne corresponde plus aux besoins initialement définis avec sa taille. Pas de panique ! Un changement est toujours possible après coup. L’un des grands avantages d’Azure est la possibilité de modifier la taille des machines virtuelles, à la volée, des besoins en termes de performances du processeur, du réseau ou de disques.

Dans cet article, nous allons démontrer ensemble la simplicité de changer la taille d’une machine virtuelle, mais également les étapes additionnelles pour un changement particulier.

Dans quel cas redimensionner ?

Lorsque l’on examine le redimensionnement de machines virtuelles sous Azure, trois axes définissent ce processus de changement de taille :

  • Localisation : votre région Azure ne contient pas le matériel nécessaire pour prendre en charge la taille de machine virtuelle souhaitée.
  • Interruption : vous devrez dans certains cas désallouer la machine virtuelle. Cela peut se produire si la nouvelle taille n’est pas disponible sur le cluster matériel qui l’héberge actuellement.
  • Restriction : Si votre machine virtuelle utilise le stockage Premium, assurez-vous que vous choisissez une version s de la taille pour obtenir le support du stockage Premium.

Tailles des machines virtuelles dans Azure

Avant de basculer sur le portail Azure pour effectuer les étapes de modification de taille, voici un rappel de l’offre des machines virtuelles Azure. Afin d’y voir plus clair, Microsoft a segmenté son offre de machines virtuelles par famille, correspondant à des scénarios de besoin utilisateur :

En exemple, voici la définition donnée par Microsoft pour des besoins GPU :

Les tailles de machine virtuelle au GPU optimisé sont des machines virtuelles spécialisées disponibles avec des GPU uniques, multiples ou fractionnaires. Ces tailles sont conçues pour des charges de travail de visualisation, mais également de calcul et d’affichage graphique intensifs.

Microsoft Doc

Les familles sont généralement couvertes par plusieurs séries. Une série est une combinaison CPU + RAM + Autre critères. Les séries sont régulièrement mis à jour par Microsoft via des versions. Voici en exemple le détail de la composition pour la série NCv3 :

Les machines virtuelles de série NCv3 sont optimisées par les GPU NVIDIA Tesla V100. Ces GPU peuvent fournir des performances de calcul une fois et demie supérieure à celles de la série NCv2… les machines virtuelles de la série NCv3 sont également pilotées par des processeurs Intel Xeon E5-2690 v4 (Broadwell).

Microsoft Doc

Enfin, chaque série dispose plusieurs SKUs pour proposer différentes puissances. Toujours en exemple, la série graphique NCv3 :

La taille de la machine virtuelle influe également sur le prix de celle-ci. Toujours en exemple, la série graphique NCv3 :

Les instances réservées, d’un ou trois ans, diminuent fortement le prix des machines virtuelles.

Codification Azure

Cette large découpe propose aux utilisateurs un très grand nombre de machines virtuelles possibles. Dans cette jungle de SKUs, Microsoft a mis en place une codification précise dans la dénomination.

[Famille] + [Sous-famille]* + [nombre de processeurs virtuels] + [Processeurs virtuels avec contraintes]* + [Fonctionnalités supplémentaires] + [Type d’accélérateur]* + [Version]
ValeurExplication
FamilleIndique la série de la famille de machines virtuelles
*Sous-familleUtilisé uniquement pour différencier des machines virtuelles spécialisées
Nombre de processeurs virtuelsIndique le nombre de processeurs virtuels de la machine virtuelle
*Processeurs virtuels avec contraintesUtilisé pour certaines tailles de machine virtuelle uniquement. Indique le nombre de processeurs virtuels pour la taille des processeurs virtuels avec contraintes
Fonctionnalités supplémentairesUne ou plusieurs lettres minuscules indiquent des fonctionnalités supplémentaires, telles que :
a = processeur basé sur AMD
b = bloquer les performances de stockage
d = diskfull (c.-à-d., un disque temporaire local présent) ; ceci concerne les nouvelles machines virtuelles Azure, consultez Séries Ddv4 et Ddsv4
i = taille isolée
l = mémoire insuffisante ; une quantité de mémoire inférieure à la taille d’utilisation intensive de la mémoire
m = utilisation intensive de la mémoire ; la plus grande quantité de mémoire dans une taille particulière
t = très petite mémoire ; la plus petite quantité de mémoire dans une taille particulière
s = capacité de stockage Premium, y compris l’utilisation possible de SSD Ultra (Remarque : certaines tailles plus récentes sans l’attribut de s peuvent toujours prendre en charge le stockage Premium, par exemple M128, M64, etc.)
*Type d’accélérateurIndique le type d’accélérateur matériel dans les références (SKU) spécialisées/GPU. Seules les nouvelles références (SKU) spécialisées/GPU lancées à partir du troisième trimestre 2020 auront l’accélérateur matériel dans leur nom.
VersionIndique la version de la série de machines virtuelles

Voici un exemple de dénomination pour la machine virtuelle graphique NC4as_T4_v3 :

ValeurExplication
FamilleN
Sous-familleC
Nombre de processeurs virtuels4
Fonctionnalités supplémentairesa = processeur basé sur AMD
s = capacité de stockage Premium
Type d’accélérateurT4
Versionv3

Avec toutes ces informations, nous allons pouvoir nous intéresser au changement de SKU sur une machine virtuelle existante.

Etape 0 : Rappel des prérequis

Pour cela, nous allons créer différentes ressources sur Azure pour y parvenir. Comme toujours, des prérequis sont nécessaires pour réaliser cette démonstration :

  • Un tenant Microsoft
  • Une souscription Azure valide
  • Une machine virtuelle déployée et démarrée

Comme le montre la copie d’écran ci-dessous, ma machine virtuelle dispose actuellement de la taille D4ds v4

Afin de mesurer les impacts d’un changement de taille sur une machine virtuelle démarrée, j’ai également ouvert une connexion RDP à celle-ci

Test I : Changement d’une taille dans la même série

Le changement de taille de la machine virtuelle s’effectue depuis le portail Azure via la section Taille.

Azure y regroupe différentes tailles, accessibles ou non :

  • Tailles de machine virtuelle les plus populaires
  • Autres séries disponibles
  • Anciennes séries toujours disponibles
  • Tailles indisponibles car problème de quota
  • Tailles indisponibles car disque incompatible
  • Tailles indisponibles car image incompatible

Jouez avec les filtres suivants pour trouver la taille adaptée

Certaines tailles ne sont même pas visibles.

Sélectionnez la taille et cliquez sur redimensionner

Une fois déclenché, une notification de traitement apparait dans votre portail Azure

La session RDP est-elle aussi coupée

Après traitement (30 secondes environ), la machine virtuelle retrouve son status démarré. La nouvelle taille se retrouve alors sur la page principale de la machine virtuelle Azure

La réouverture manuelle de la session RDP montre bien la nouvelle puissance

Test II : Changement d’une taille dans une série disponible

Continuez vos tests en effectuant un changement de taille vers une autre famille de machine virtuelle

Là encore, la session RDP se ferme et la notification de changement apparaît sur le portail Azure. Moins d’une minute plus tard, la machine virtuelle repart avec sa dernière taille

Test III : Changement d’une taille dans une série disponible

Dans certains cas, il est nécessaire de partir sur une taille de machine virtuelle ayant des propriétés différentes. Ma machine virtuelle, actuellement en Standard F8s v2, dispose d’un stockage temporaire.

Le disque temporaire est très utile pour les données qui, vous l’aurez deviné, sont de nature temporaire. Un excellent exemple de ce type de données pour Windows est le pagefile. Lorsqu’une nouvelle machine virtuelle Windows est provisionnée à partir d’une image dans Azure, le pagefile est configuré si cela est possible pour qu’il soit situé sur ce disque temporaire.

Ce stockage temporaire se retrouve alors sur le disque D

Pour la plupart des machines virtuelles Windows, le volume sur le disque temporaire à la lettre de lecteur D:.
Il a également l’étiquette de lecteur « Temporary Storage ».

Les clients ne doivent pas utiliser le disque temporaire pour des données qui doivent être persistantes.

Un retour dans la liste des tailles disponibles pour ma machine virtuelle vm001 ne permet pas de choisir une machine virtuelle dépourvue de disque temporaire.

Dans ce cas, pas le choix, la recréation d’une nouvelle machine virtuelle est un passage obligatoire.

Etape I : Créer une sauvegarde du ou des disques présents

Allez sur la page des disques de la machine virtuelle et cliquez sur chacun d’eux

Créez une sauvegarde de chaque disque (OS et Data)

Vérifiez les champs et lancez la création

Une fois terminé, cliquez ici pour accéder au snapshot

Etape II : Créez un ou des disques depuis la ou les sauvegardes

Lancez la création du ou des nouveaux disques depuis le ou les snapshots créés

Une fois terminé, cliquez ici pour accéder au disque créé

Etape III : Création de la nouvelle machine virtuelle

Il ne reste plus qu’à rattacher ce ou ces disques à une nouvelle machine virtuelle

Renseignez tous les champs nécessaires et la nouvelle taille de machine désirée

Lancez la création de la machine virtuelle

Cliquez ici pour retrouver les propriétés de votre nouvelle machine virtuelle

Constatez la bonne taille de votre machine virtuelle Standard D4s v4

Rouvrez une session RDP sur cette nouvelle machine virtuelle pour finaliser les réglages de pagefile. Un message d’avertissement apparaît à l’ouverture de la session

Sélectionnez les paramétrages automatiques Windows

Redémarrez la machine virtuelle pour appliquer les modifications pagefile

Et vous voilà avec la nouvelle taille ????

Conclusion

Azure apporte beaucoup de flexibilité avec le changement de taille pour les machines virtuelles. Il est même possible de scripter le changement de taille selon les besoins ou les pics de charges.

Comme toujours John nous propose une vidéo pour aller plus loin sur ce sujet ????