Optimiser les I/O disque sous Linux : Guide Avance pour la Production
Quand on travaille avec des bases de donnees, des systemes distribues comme Apache Kafka, ou des workloads containerises intensifs, les performances disque deviennent rapidement un point de contention. Ce guide complet vous permettra de tirer le meilleur de vos I/O.
Architecture du Stack I/O Linux
<svg viewBox="0 0 800 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="appGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#8b5cf6"/>
<stop offset="100%" style="stop-color:#7c3aed"/>
</linearGradient>
<linearGradient id="kernelGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#f97316"/>
<stop offset="100%" style="stop-color:#ea580c"/>
</linearGradient>
<linearGradient id="hwGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#22c55e"/>
<stop offset="100%" style="stop-color:#16a34a"/>
</linearGradient>
</defs>
<rect width="800" height="500" fill="#0f172a"/>
<!-- Application Layer -->
<rect x="150" y="30" width="500" height="60" rx="8" fill="url(#appGrad)"/>
<text x="400" y="65" text-anchor="middle" fill="white" font-size="16" font-weight="bold">Application (PostgreSQL, Kafka, etc.)</text>
<!-- VFS Layer -->
<rect x="150" y="110" width="500" height="50" rx="8" fill="#3b82f6"/>
<text x="400" y="140" text-anchor="middle" fill="white" font-size="14" font-weight="bold">VFS (Virtual File System)</text>
<!-- Page Cache -->
<rect x="150" y="180" width="240" height="50" rx="8" fill="#06b6d4"/>
<text x="270" y="210" text-anchor="middle" fill="white" font-size="13" font-weight="bold">Page Cache</text>
<rect x="410" y="180" width="240" height="50" rx="8" fill="#06b6d4"/>
<text x="530" y="210" text-anchor="middle" fill="white" font-size="13" font-weight="bold">Buffer Cache</text>
<!-- Filesystem -->
<rect x="150" y="250" width="150" height="50" rx="8" fill="url(#kernelGrad)"/>
<text x="225" y="280" text-anchor="middle" fill="white" font-size="12" font-weight="bold">ext4</text>
<rect x="320" y="250" width="150" height="50" rx="8" fill="url(#kernelGrad)"/>
<text x="395" y="280" text-anchor="middle" fill="white" font-size="12" font-weight="bold">XFS</text>
<rect x="490" y="250" width="160" height="50" rx="8" fill="url(#kernelGrad)"/>
<text x="570" y="280" text-anchor="middle" fill="white" font-size="12" font-weight="bold">ZFS/Btrfs</text>
<!-- Block Layer -->
<rect x="150" y="320" width="500" height="50" rx="8" fill="#ec4899"/>
<text x="400" y="350" text-anchor="middle" fill="white" font-size="14" font-weight="bold">Block Layer (I/O Scheduler: none, mq-deadline, bfq)</text>
<!-- Device Drivers -->
<rect x="150" y="390" width="240" height="45" rx="8" fill="#a855f7"/>
<text x="270" y="418" text-anchor="middle" fill="white" font-size="12" font-weight="bold">NVMe Driver</text>
<rect x="410" y="390" width="240" height="45" rx="8" fill="#a855f7"/>
<text x="530" y="418" text-anchor="middle" fill="white" font-size="12" font-weight="bold">SCSI/SATA Driver</text>
<!-- Hardware -->
<rect x="150" y="455" width="500" height="35" rx="8" fill="url(#hwGrad)"/>
<text x="400" y="478" text-anchor="middle" fill="white" font-size="14" font-weight="bold">Hardware: NVMe SSD / SATA SSD / HDD</text>
<!-- Arrows -->
<path d="M400 90 L400 110" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<path d="M400 160 L400 180" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<path d="M400 230 L400 250" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<path d="M400 300 L400 320" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<path d="M400 370 L400 390" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<path d="M400 435 L400 455" stroke="#94a3b8" stroke-width="2" marker-end="url(#ioArrow)"/>
<defs>
<marker id="ioArrow" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#94a3b8"/>
</marker>
</defs>
</svg>
Pourquoi optimiser les I/O ?
Sans tuning, un disque rapide (NVMe, SSD) peut etre severement bride par :
- Un mauvais choix de systeme de fichiers
- Des options de montage par defaut inefficaces
- Un scheduler I/O inadapte
- Une mauvaise configuration du cache memoire
- Un alignement de partition sous-optimal
Impact reel mesure
| Composant | Avant tuning | Apres tuning | Gain |
|---|---|---|---|
| IOPS 4K random | 45,000 | 180,000 | +300% |
| Latence moyenne | 0.8ms | 0.2ms | -75% |
| Debit sequentiel | 1.2 GB/s | 3.2 GB/s | +167% |
| CPU wait I/O | 15% | 3% | -80% |
Choix du systeme de fichiers
Comparaison des filesystems
| Filesystem | Lectures aleatoires | Ecritures seq. | Metadata | Snapshots | Cas d'usage |
|---|---|---|---|---|---|
| ext4 | Excellent | Bon | Bon | Non | General, petits fichiers |
| XFS | Tres bon | Excellent | Excellent | Non | BDD, logs, gros fichiers |
| ZFS | Bon | Bon | Excellent | Oui | Stockage, backup, integrite |
| Btrfs | Bon | Moyen | Bon | Oui | Dev, snapshots frequents |
ext4 : classique mais solide
# Creation optimisee ext4
mkfs.ext4 -F \
-E stride=128,stripe_width=256 \ # Alignement RAID
-O dir_index,extent,flex_bg \ # Features modernes
-b 4096 \ # Block size 4K
-i 16384 \ # Plus d'inodes
/dev/nvme0n1p1
XFS : pour les workloads intensifs
# Creation optimisee XFS
mkfs.xfs -f \
-d agcount=32 \ # Plus d'allocation groups (parallelisme)
-l size=512m \ # Log interne plus grand
-n size=8192 \ # Directory block size
-i maxpct=25 \ # Plus d'espace pour les inodes
/dev/nvme0n1p1
ZFS : avec de la RAM
# Creation pool ZFS
zpool create -o ashift=12 tank /dev/nvme0n1
# Dataset optimise
zfs create tank/data
zfs set atime=off tank/data
zfs set compression=lz4 tank/data
zfs set recordsize=128k tank/data # Pour bases de donnees
zfs set xattr=sa tank/data
zfs set dnodesize=auto tank/data
zfs set sync=standard tank/data # ou disabled pour max perf (risque)
# Tuning ARC (cache)
echo 8589934592 > /sys/module/zfs/parameters/zfs_arc_max # 8GB max
Options de montage recommandees
Pour ext4 (Production)
# /etc/fstab
UUID=xxxx /data ext4 defaults,noatime,nodiratime,discard,barrier=0,data=writeback,errors=remount-ro 0 2
| Option | Description | Impact |
|---|---|---|
noatime |
Pas de MAJ timestamp acces | -20% I/O |
nodiratime |
Idem pour directories | -5% I/O |
discard |
TRIM automatique pour SSD | Longevite SSD |
barrier=0 |
Desactive barriere ecriture | +15% perf (avec UPS) |
data=writeback |
Ecriture asynchrone | +10% perf |
Pour XFS (Production)
# /etc/fstab
UUID=xxxx /data xfs defaults,noatime,nodiratime,discard,nobarrier,logbufs=8,logbsize=256k,allocsize=64m 0 2
| Option | Description | Impact |
|---|---|---|
logbufs=8 |
8 buffers de log (defaut: 4) | +10% ecriture |
logbsize=256k |
Taille buffer log 256K | +5% ecriture |
allocsize=64m |
Pre-allocation 64MB | +20% gros fichiers |
nobarrier |
Desactive barrieres | +15% perf |
Pour tmpfs (RAM disk)
# /etc/fstab - Pour caches temporaires
tmpfs /tmp tmpfs defaults,noatime,mode=1777,size=4G 0 0
tmpfs /var/cache/nginx tmpfs defaults,noatime,size=1G,uid=nginx,gid=nginx 0 0
Configuration du scheduler I/O
<svg viewBox="0 0 800 250" xmlns="http://www.w3.org/2000/svg">
<rect width="800" height="250" fill="#0f172a"/>
<!-- None/NOOP -->
<g transform="translate(130, 120)">
<rect x="-100" y="-60" width="200" height="120" rx="10" fill="#1e293b" stroke="#22c55e" stroke-width="3"/>
<text y="-30" text-anchor="middle" fill="#22c55e" font-size="16" font-weight="bold">none (NOOP)</text>
<text y="0" text-anchor="middle" fill="#94a3b8" font-size="11">FIFO simple</text>
<text y="20" text-anchor="middle" fill="#64748b" font-size="10">Latence minimale</text>
<text y="50" text-anchor="middle" fill="#22c55e" font-size="12" font-weight="bold">NVMe / SSD</text>
</g>
<!-- mq-deadline -->
<g transform="translate(400, 120)">
<rect x="-100" y="-60" width="200" height="120" rx="10" fill="#1e293b" stroke="#3b82f6" stroke-width="3"/>
<text y="-30" text-anchor="middle" fill="#3b82f6" font-size="16" font-weight="bold">mq-deadline</text>
<text y="0" text-anchor="middle" fill="#94a3b8" font-size="11">Deadlines garanties</text>
<text y="20" text-anchor="middle" fill="#64748b" font-size="10">Equite lecture/ecriture</text>
<text y="50" text-anchor="middle" fill="#3b82f6" font-size="12" font-weight="bold">HDD / SATA SSD</text>
</g>
<!-- BFQ -->
<g transform="translate(670, 120)">
<rect x="-100" y="-60" width="200" height="120" rx="10" fill="#1e293b" stroke="#f97316" stroke-width="3"/>
<text y="-30" text-anchor="middle" fill="#f97316" font-size="16" font-weight="bold">bfq</text>
<text y="0" text-anchor="middle" fill="#94a3b8" font-size="11">Budget Fair Queuing</text>
<text y="20" text-anchor="middle" fill="#64748b" font-size="10">Latence interactive</text>
<text y="50" text-anchor="middle" fill="#f97316" font-size="12" font-weight="bold">Desktop / Multi-user</text>
</g>
<text x="400" y="230" text-anchor="middle" fill="#64748b" font-size="13">Choisir le scheduler selon le type de disque et le workload</text>
</svg>
Verifier le scheduler actuel
# Pour tous les disques
for disk in /sys/block/*/queue/scheduler; do
echo "$disk: $(cat $disk)"
done
# Exemple de sortie:
# /sys/block/nvme0n1/queue/scheduler: [none] mq-deadline kyber bfq
# /sys/block/sda/queue/scheduler: none [mq-deadline] kyber bfq
Configuration dynamique
# Pour SSD/NVMe - utiliser none (NOOP)
echo none > /sys/block/nvme0n1/queue/scheduler
# Pour HDD - utiliser mq-deadline
echo mq-deadline > /sys/block/sda/queue/scheduler
# Pour desktop/interactif - utiliser bfq
echo bfq > /sys/block/sda/queue/scheduler
Configuration permanente via udev
# /etc/udev/rules.d/60-io-schedulers.rules
# NVMe - toujours none
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
# SSD SATA (non rotatif) - none
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none"
# HDD (rotatif) - mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="mq-deadline"
# Recharger les regles
udevadm control --reload-rules && udevadm trigger
Tuning du cache et de la memoire virtuelle
Parametres critiques
# /etc/sysctl.d/99-io-performance.conf
# === SWAPPINESS ===
# Reduire l'utilisation du swap (valeur 1-10 pour serveurs)
vm.swappiness = 1
# === DIRTY PAGES ===
# Quand commencer a ecrire les dirty pages en arriere-plan
vm.dirty_background_ratio = 5 # 5% de la RAM
# Quand bloquer les processus pour forcer l'ecriture
vm.dirty_ratio = 15 # 15% de la RAM
# Duree avant d'ecrire les dirty pages (centisecondes)
vm.dirty_expire_centisecs = 3000 # 30 secondes
vm.dirty_writeback_centisecs = 500 # Reveil toutes les 5 secondes
# === POUR SERVEURS AVEC BEAUCOUP DE RAM ===
# Alternative avec valeurs fixes (mieux pour grosse RAM)
# vm.dirty_background_bytes = 268435456 # 256MB
# vm.dirty_bytes = 536870912 # 512MB
# === CACHE VFS ===
# Pression sur le cache dentries/inodes (100 = normal, 50 = moins agressif)
vm.vfs_cache_pressure = 50
# === OVERCOMMIT ===
# 0 = heuristic, 1 = always, 2 = never
vm.overcommit_memory = 0
vm.overcommit_ratio = 50
# === PAGE CACHE ===
# Minimum de pages libres (en pages de 4K)
vm.min_free_kbytes = 262144 # 256MB
# === ZONE RECLAIM ===
# Desactiver pour NUMA (evite latences)
vm.zone_reclaim_mode = 0
Application et verification
# Appliquer
sysctl -p /etc/sysctl.d/99-io-performance.conf
# Verifier
sysctl -a | grep -E "dirty|swap|cache_pressure"
# Voir l'etat actuel du cache
free -h
cat /proc/meminfo | grep -E "Dirty|Writeback|Cached|Buffers"
Queue depth et parametres avances
Pour NVMe haute performance
# /etc/udev/rules.d/61-nvme-tuning.rules
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/nr_requests}="1024"
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/read_ahead_kb}="256"
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/rq_affinity}="2"
| Parametre | Description | Valeur recommandee |
|---|---|---|
nr_requests |
Taille de la queue | 256-1024 pour NVMe |
read_ahead_kb |
Pre-lecture | 256-512 pour sequentiel |
rq_affinity |
Affinite CPU | 2 pour localite NUMA |
nomerges |
Desactive fusion I/O | 0 (garder les merges) |
Pour SSD SATA
# Parametres plus conservateurs
echo 64 > /sys/block/sda/queue/nr_requests
echo 128 > /sys/block/sda/queue/read_ahead_kb
echo 0 > /sys/block/sda/queue/add_random
Pour HDD
# Optimise pour acces sequentiel
echo 128 > /sys/block/sdb/queue/nr_requests
echo 4096 > /sys/block/sdb/queue/read_ahead_kb # 4MB read-ahead
echo 1 > /sys/block/sdb/queue/iosched/fifo_batch
RAID et LVM
RAID logiciel (mdadm)
# Creation RAID 10 optimise
mdadm --create /dev/md0 --level=10 --raid-devices=4 \
--chunk=256K \
/dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1 /dev/nvme3n1
# Tuning du RAID
echo 32768 > /sys/block/md0/md/stripe_cache_size
echo 4096 > /sys/block/md0/queue/read_ahead_kb
# /etc/mdadm.conf
ARRAY /dev/md0 metadata=1.2 UUID=xxxx
LVM optimise
# Creer PV avec alignement
pvcreate --dataalignment 1m /dev/nvme0n1
# Creer VG
vgcreate -s 32M vg_data /dev/nvme0n1
# Creer LV avec stripping (si plusieurs PV)
lvcreate -L 100G -n lv_data -i 4 -I 256K vg_data
# Tuning read-ahead LVM
lvchange --readahead 256 vg_data/lv_data
Configurations specifiques aux workloads
Apache Kafka
# XFS optimise pour Kafka (logs sequentiels)
mkfs.xfs -f -d agcount=32 -l size=512m -n size=8192 /dev/nvme0n1p1
# Montage
mount -o noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k,allocsize=64m \
/dev/nvme0n1p1 /var/lib/kafka
# sysctl pour Kafka
vm.dirty_background_ratio = 5
vm.dirty_ratio = 80 # Plus eleve pour Kafka
vm.dirty_expire_centisecs = 30000 # 5 minutes
# Kafka broker.properties
log.segment.bytes=1073741824
log.flush.interval.messages=10000
log.flush.interval.ms=1000
log.preallocate=true
PostgreSQL
# XFS optimise pour PostgreSQL
mkfs.xfs -f -d agcount=16 -l size=256m -n size=8192 /dev/nvme0n1p1
# Montage pour PostgreSQL
mount -o noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k \
/dev/nvme0n1p1 /var/lib/postgresql
# postgresql.conf complementaire
shared_buffers = 8GB # 25% de la RAM
effective_cache_size = 24GB # 75% de la RAM
maintenance_work_mem = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 64MB
wal_compression = on
synchronous_commit = off # Si acceptable
Elasticsearch
# Montage pour Elasticsearch
mount -o noatime,nodiratime,nobarrier \
/dev/nvme0n1p1 /var/lib/elasticsearch
# sysctl pour Elasticsearch
vm.max_map_count = 262144
vm.swappiness = 1
# elasticsearch.yml
bootstrap.memory_lock: true
indices.memory.index_buffer_size: 30%
Conteneurs/Kubernetes
# XFS avec ftype=1 pour overlay2
mkfs.xfs -f -n ftype=1 /dev/nvme0n1p1
# Montage pour containerd
mount -o noatime,nodiratime,nobarrier,prjquota \
/dev/nvme0n1p1 /var/lib/containerd
# containerd config.toml
[plugins."io.containerd.snapshotter.v1.overlayfs"]
root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs"
Benchmarking avec fio
Test complet de performance
#!/bin/bash
# benchmark-disk.sh
DEVICE="/dev/nvme0n1"
MOUNT="/data"
SIZE="10G"
RUNTIME="60"
echo "=== Benchmark I/O sur $MOUNT ==="
# 1. Lecture sequentielle
echo -e "\n--- Lecture sequentielle (1MB blocks) ---"
fio --name=seq-read \
--ioengine=libaio \
--rw=read \
--bs=1M \
--numjobs=4 \
--iodepth=32 \
--runtime=$RUNTIME \
--time_based \
--filename=$MOUNT/testfile \
--size=$SIZE \
--group_reporting
# 2. Ecriture sequentielle
echo -e "\n--- Ecriture sequentielle (1MB blocks) ---"
fio --name=seq-write \
--ioengine=libaio \
--rw=write \
--bs=1M \
--numjobs=4 \
--iodepth=32 \
--runtime=$RUNTIME \
--time_based \
--filename=$MOUNT/testfile \
--size=$SIZE \
--group_reporting
# 3. Lecture aleatoire 4K
echo -e "\n--- Lecture aleatoire 4K ---"
fio --name=rand-read-4k \
--ioengine=libaio \
--rw=randread \
--bs=4k \
--numjobs=8 \
--iodepth=64 \
--runtime=$RUNTIME \
--time_based \
--filename=$MOUNT/testfile \
--size=$SIZE \
--group_reporting
# 4. Ecriture aleatoire 4K
echo -e "\n--- Ecriture aleatoire 4K ---"
fio --name=rand-write-4k \
--ioengine=libaio \
--rw=randwrite \
--bs=4k \
--numjobs=8 \
--iodepth=64 \
--runtime=$RUNTIME \
--time_based \
--filename=$MOUNT/testfile \
--size=$SIZE \
--group_reporting
# 5. Workload mixte (70/30)
echo -e "\n--- Workload mixte 70% lecture / 30% ecriture ---"
fio --name=mixed-rw \
--ioengine=libaio \
--rw=randrw \
--rwmixread=70 \
--bs=8k \
--numjobs=8 \
--iodepth=32 \
--runtime=$RUNTIME \
--time_based \
--filename=$MOUNT/testfile \
--size=$SIZE \
--group_reporting
# 6. Test latence
echo -e "\n--- Test latence (iodepth=1) ---"
fio --name=latency \
--ioengine=libaio \
--rw=randread \
--bs=4k \
--numjobs=1 \
--iodepth=1 \
--runtime=30 \
--time_based \
--filename=$MOUNT/testfile \
--size=1G \
--group_reporting \
--lat_percentiles=1
# Cleanup
rm -f $MOUNT/testfile
echo -e "\n=== Benchmark termine ==="
Resultats attendus
| Test | NVMe Gen4 | NVMe Gen3 | SATA SSD | HDD |
|---|---|---|---|---|
| Seq Read | 6-7 GB/s | 3-3.5 GB/s | 500-550 MB/s | 150-200 MB/s |
| Seq Write | 5-6 GB/s | 2.5-3 GB/s | 450-500 MB/s | 130-180 MB/s |
| 4K Rand Read | 800K-1M IOPS | 400-500K IOPS | 80-100K IOPS | 100-200 IOPS |
| 4K Rand Write | 200-400K IOPS | 100-200K IOPS | 40-60K IOPS | 100-200 IOPS |
| Latence 4K | < 0.1ms | 0.1-0.2ms | 0.3-0.5ms | 5-15ms |
Monitoring en temps reel
iostat
# Statistiques detaillees toutes les 2 secondes
iostat -xdh 2
# Metriques cles:
# %util : Utilisation disque (>80% = saturation)
# await : Latence moyenne totale (ms)
# r_await/w_await : Latence lecture/ecriture
# avgqu-sz : Profondeur moyenne de la queue
# r/s, w/s : IOPS lecture/ecriture
# rMB/s, wMB/s : Debit MB/s
iotop
# Processus consommant le plus d'I/O
iotop -o -P -d 1
# -o : Seulement les processus avec I/O
# -P : Afficher les processus (pas threads)
# -d 1 : Refresh toutes les secondes
blktrace/blkparse
# Trace detaillee des I/O
blktrace -d /dev/nvme0n1 -o trace
# Analyse
blkparse trace.blktrace.0 | head -100
# Visualisation
btt -i trace.blktrace.0
Prometheus/Grafana
# node_exporter collecte automatiquement les metriques disque
# Metriques utiles:
# - node_disk_io_time_seconds_total
# - node_disk_read_bytes_total
# - node_disk_written_bytes_total
# - node_disk_io_now
# - node_disk_read_time_seconds_total
# - node_disk_write_time_seconds_total
Troubleshooting
Probleme 1: I/O Wait eleve
# Diagnostic
vmstat 1 5
# Colonne 'wa' = I/O wait %
iostat -x 1 5
# %util proche de 100% = disque sature
# Solutions:
# 1. Verifier le scheduler
cat /sys/block/nvme0n1/queue/scheduler
# 2. Verifier les dirty pages
cat /proc/meminfo | grep Dirty
# Si tres eleve: reduire vm.dirty_ratio
# 3. Identifier le processus fautif
iotop -o -P
Probleme 2: Latence elevee
# Diagnostic
iostat -x 1
# await > 10ms sur SSD = probleme
# Causes possibles:
# 1. Queue trop profonde
cat /sys/block/nvme0n1/queue/nr_requests
# Reduire si necessaire
# 2. Scheduler inadapte
# Utiliser 'none' pour NVMe
# 3. TRIM non configure
fstrim -v /data
# Ajouter discard au montage ou cron fstrim
Probleme 3: Debit insuffisant
# Diagnostic
hdparm -Tt /dev/nvme0n1
# Verifier l'alignement des partitions
parted /dev/nvme0n1 align-check opt 1
# Verifier le mode de transfert (SATA)
hdparm -I /dev/sda | grep -i speed
# Solutions:
# 1. Augmenter read_ahead_kb
echo 512 > /sys/block/nvme0n1/queue/read_ahead_kb
# 2. Verifier les options de montage
mount | grep /data
Probleme 4: SSD qui ralentit avec le temps
# Verifier l'etat SMART
smartctl -a /dev/nvme0n1
# Verifier l'usure
nvme smart-log /dev/nvme0n1
# Solutions:
# 1. Activer le TRIM
fstrim -av
# 2. TRIM periodique
# /etc/cron.weekly/fstrim
#!/bin/bash
fstrim -av
# 3. Verifier l'over-provisioning
# Garder 10-20% d'espace libre
Checklist de production
## Pre-mise en production
### Filesystem
- [ ] Filesystem adapte au workload (XFS pour BDD, ext4 general)
- [ ] Options de montage optimisees (noatime, nobarrier)
- [ ] Partitions alignees (multiple de 4K)
- [ ] TRIM configure (discard ou cron fstrim)
### Scheduler
- [ ] Scheduler I/O adapte (none pour NVMe, mq-deadline pour HDD)
- [ ] Queue depth configure
- [ ] Rules udev persistantes
### Kernel
- [ ] vm.swappiness reduit
- [ ] vm.dirty_* ajustes
- [ ] vm.vfs_cache_pressure ajuste
### Monitoring
- [ ] iostat/iotop disponibles
- [ ] Metriques Prometheus configurees
- [ ] Alertes sur %util et latence
### Benchmarks
- [ ] Tests fio realises
- [ ] Resultats conformes aux specs disque
- [ ] Comparaison avant/apres tuning documentee
Conclusion
L'optimisation des I/O disque sous Linux necessite une approche holistique combinant choix du filesystem, tuning du kernel, et configuration adaptee au workload.
Points cles a retenir:
- Scheduler :
nonepour NVMe/SSD,mq-deadlinepour HDD - Montage : Toujours
noatime,nobarriersi UPS disponible - Cache : Ajuster
vm.dirty_*selon la charge d'ecriture - Monitoring :
iostat -xest votre meilleur ami - Tests : Toujours benchmarker avant et apres tuning
Les gains peuvent etre spectaculaires : +300% en IOPS, -75% en latence.
Ressources
- Linux Block Layer Documentation
- fio Documentation
- XFS Documentation
- Red Hat Performance Tuning Guide
Besoin d'aide pour optimiser les performances de vos serveurs Linux ? Decouvrez mes services de consulting et audits de performance.