Avancé
⭐ Article vedette

Optimiser les I/O disque sous Linux : Guide Avancé pour la Production

Tuning avancé des performances disque sur Linux : filesystem, scheduler, cache, partitionnement et benchmarks.

Publié le
1 novembre 2024
Lecture
14 min
Vues
982
Auteur
Florian Courouge
Linux
IO
Disque
Performance
Sysadmin
SSD
XFS

Table des matières

📋 Vue d'ensemble rapide des sujets traités dans cet article

Cliquez sur les sections ci-dessous pour naviguer rapidement

Optimiser les I/O disque sous Linux : Guide Avancé pour la Production

Quand on travaille avec des bases de données, des systèmes distribués ou des workloads conteneurisés intensifs, les performances disque deviennent rapidement un point de contention. Voici un guide complet pour tuner votre machine Linux et tirer le meilleur des I/O.

Linux I/O Stack

💡Pourquoi optimiser les I/O ?

Sans tuning, un disque rapide (NVMe, SSD) peut être sévèrement bridé par :

  • Un mauvais choix de système de fichiers
  • Des options de montage par défaut inefficaces
  • Un scheduler I/O inadapté
  • Une mauvaise configuration du cache mémoire
  • Un alignement de partition sous-optimal

💡Choix du système de fichiers

Filesystem Comparison

ext4 : classique mais solide

  • Avantages : Bonne compatibilité et robustesse
  • Inconvénients : Moins efficace sur les workloads très parallèles

xfs : pour l'écriture séquentielle

  • Avantages : Parfait pour les bases de données, logs, fichiers volumineux
  • Inconvénients : Moins performant sur les petites écritures aléatoires

zfs : avec de la RAM

  • Avantages : Compression, snapshots, intégrité
  • Inconvénients : Overhead mémoire non négligeable

💡Options de montage recommandées

Pour ext4 :

UUID=xxxx /data ext4 defaults,noatime,nodiratime,barrier=0,data=writeback 0 2

Explications :

  • noatime,nodiratime : désactive la mise à jour des timestamps d'accès (-20% d'I/O)
  • barrier=0 : désactive les barrières d'écriture (gain notable sur SSD/NVMe)
  • data=writeback : mode d'écriture asynchrone le plus rapide

Pour xfs :

UUID=xxxx /data xfs defaults,noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k 0 2

Explications :

  • logbufs=8 : augmente le nombre de buffers de log
  • logbsize=256k : taille optimisée des buffers de log

Pour zfs :

# Configuration via zfs set
zfs set atime=off tank/data
zfs set compression=lz4 tank/data
zfs set recordsize=128k tank/data  # Pour bases de données
zfs set primarycache=metadata tank/data  # Si peu de RAM

💡Configuration du scheduler I/O

I/O Schedulers

Le scheduler par défaut n'est pas toujours optimal selon le type de disque.

Vérifier le scheduler actuel :

cat /sys/block/nvme0n1/queue/scheduler
# [mq-deadline] kyber bfq none

Pour SSD/NVMe :

# none (NOOP) - délègue tout au contrôleur SSD
echo none > /sys/block/nvme0n1/queue/scheduler

# Permanent via kernel parameter
# GRUB_CMDLINE_LINUX="elevator=none"

Pour HDD :

# mq-deadline - optimisé pour les disques rotatifs
echo mq-deadline > /sys/block/sda/queue/scheduler

Configuration permanente :

# /etc/udev/rules.d/60-schedulers.rules
# SSD/NVMe
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none"

# HDD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="mq-deadline"

💡Tuning du cache et de la mémoire virtuelle

Linux Memory Management

Paramètres /proc/sys/vm/ critiques :

# /etc/sysctl.d/99-io-performance.conf

# Réduire la swapiness (sauf si swap obligatoire)
vm.swappiness = 1

# Dirty pages - crucial pour les écritures
vm.dirty_background_ratio = 5    # Début écriture asynchrone à 5% RAM
vm.dirty_ratio = 10              # Blocage processus à 10% RAM
vm.dirty_expire_centisecs = 1000 # Flush dirty pages après 10s
vm.dirty_writeback_centisecs = 500 # Réveil pdflush toutes les 5s

# Pour workloads avec beaucoup d'écritures séquentielles
vm.dirty_background_bytes = 67108864   # 64MB
vm.dirty_bytes = 134217728             # 128MB

# Cache de la dentries/inodes
vm.vfs_cache_pressure = 50  # Réduit la pression sur les caches VFS

Application immédiate :

sysctl -p /etc/sysctl.d/99-io-performance.conf

💡Queue depth et paramètres avancés

Pour NVMe :

# Augmenter la queue depth
echo 32 > /sys/block/nvme0n1/queue/nr_requests

# Désactiver NCQ si problématique
echo 1 > /sys/block/nvme0n1/queue/nomerges

# Read-ahead optimisé pour séquentiel
echo 256 > /sys/block/nvme0n1/queue/read_ahead_kb

Pour SSD SATA :

echo 16 > /sys/block/sda/queue/nr_requests
echo 128 > /sys/block/sda/queue/read_ahead_kb

💡Alignement des partitions

Partition Alignment

Vérification de l'alignement :

# Doit être multiple de 4096 (4K) pour les SSD modernes
sudo fdisk -l /dev/nvme0n1
# Start doit être divisible par 2048 (secteurs de 512B = 1MB)

Création de partition alignée :

# parted avec alignement optimal
sudo parted -s -a optimal /dev/nvme0n1 mklabel gpt
sudo parted -s -a optimal /dev/nvme0n1 mkpart primary 0% 100%

💡Optimisations spécifiques aux workloads

Base de données (PostgreSQL/MySQL) :

# XFS avec des paramètres spécifiques
mkfs.xfs -f -d agcount=16 -l size=256m -n size=8192 /dev/nvme0n1p1

# Options de montage
mount -o noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k,allocsize=16m /dev/nvme0n1p1 /var/lib/postgresql

Logs et écritures séquentielles :

# ext4 optimisé pour les logs
mkfs.ext4 -F -E stride=32,stripe-width=32 -b 4096 /dev/nvme0n1p2

# Montage avec writeback
mount -o noatime,data=writeback,barrier=0,nobh /dev/nvme0n1p2 /var/log

Conteneurs/Kubernetes :

# XFS pour le runtime containerd/docker
mkfs.xfs -f -n ftype=1 /dev/nvme0n1p3
mount -o noatime,nodiratime,nobarrier,prjquota /dev/nvme0n1p3 /var/lib/containerd

💡Benchmarking et monitoring

I/O Performance Monitoring

Test des performances avec fio :

Test lecture aléatoire 4K :

fio --name=random-read --ioengine=libaio --rw=randread --bs=4k --numjobs=4 \
    --iodepth=32 --runtime=60 --time_based --filename=/data/testfile --size=4G

Test écriture séquentielle :

fio --name=seq-write --ioengine=libaio --rw=write --bs=1M --numjobs=1 \
    --iodepth=4 --runtime=60 --time_based --filename=/data/testfile --size=4G

Test mixte réaliste :

fio --name=mixed-workload --ioengine=libaio --rw=randrw --rwmixread=70 \
    --bs=8k --numjobs=8 --iodepth=16 --runtime=300 --filename=/data/testfile --size=8G

Monitoring en temps réel :

iostat pour surveiller les performances :

# Statistiques détaillées toutes les 2 secondes
iostat -x 2

# Métriques clés à surveiller :
# %util    : utilisation du disque (>80% = saturé)
# await    : latence moyenne (ms)
# r/s, w/s : IOPS lecture/écriture
# rkB/s, wkB/s : débit Ko/s

iotop pour identifier les processus gourmands :

iotop -o -d 1

Avec dstat pour vue globale :

dstat -tdD sda,nvme0n1 1

💡Configuration pour environnements spécifiques

Kubernetes/containerd :

# /etc/systemd/system/kubelet.service.d/20-io-tuning.conf
[Service]
ExecStartPre=/bin/bash -c 'echo none > /sys/block/nvme0n1/queue/scheduler'
ExecStartPre=/bin/bash -c 'echo 32 > /sys/block/nvme0n1/queue/nr_requests'

Base de données haute performance :

# Configuration PostgreSQL complémentaire
# shared_buffers = 25% de la RAM
# effective_cache_size = 75% de la RAM
# checkpoint_completion_target = 0.9
# wal_buffers = 16MB
# wal_compression = on (PG 14+)

💡Validation des optimisations

Script de test automatisé :

#!/bin/bash
# test-io-performance.sh

DEVICE="/dev/nvme0n1"
MOUNT_POINT="/benchmark"

echo "=== Test performance I/O sur $DEVICE ==="

# Lecture séquentielle
echo "Test lecture séquentielle 1GB..."
dd if=$DEVICE of=/dev/null bs=1M count=1024 iflag=direct 2>&1 | grep -v records

# Écriture séquentielle (ATTENTION : destructif)
echo "Test écriture séquentielle 1GB..."
dd if=/dev/zero of=$MOUNT_POINT/testfile bs=1M count=1024 oflag=direct,sync 2>&1 | grep -v records

# Latence
echo "Test latence aléatoire..."
fio --name=latency-test --ioengine=libaio --rw=randread --bs=4k \
    --numjobs=1 --iodepth=1 --runtime=10 --filename=$MOUNT_POINT/testfile \
    --size=1G --output-format=terse | awk -F';' '{print "Latence moyenne: " $40 "us"}'

rm -f $MOUNT_POINT/testfile

💡Checklist de production

Avant mise en production :

Surveillance continue :

💡Conclusion

L'optimisation des I/O disque sous Linux nécessite une approche holistique combinant choix du filesystem, tuning du kernel, et configuration adaptée au workload. Les gains peuvent être spectaculaires : +200% en IOPS, -50% en latence.

Points clés à retenir :

N'oubliez pas : toujours tester en environnement de développement avant de déployer en production, et garder une sauvegarde de la configuration de base.

À propos de l'auteur

Florian Courouge - Expert DevOps et Apache Kafka avec plus de 5 ans d'expérience dans l'architecture de systèmes distribués et l'automatisation d'infrastructures.

Cet article vous a été utile ?

Découvrez mes autres articles techniques ou contactez-moi pour discuter de vos projets DevOps et Kafka.