Aller au contenu

Clusters et parallélisme

Passer d'une machine a plusieurs — architectures, lois de scaling et calcul haute performance.


Pourquoi les clusters

Un serveur unique, même puissant, a des limites physiques : nombre de cœurs, quantite de RAM, débit I/O. Quand ces limites sont atteintes, deux options existent : acheter une machine plus grosse (scale-up) ou ajouter des machines (scale-out). Le cluster est la réponse scale-out.

Un cluster est un ensemble de machines indépendantes (nœuds) qui cooperent pour fournir un service. L'architecture interne du cluster — comment les nœuds partagent (ou non) les ressources — détermine ses propriétés de performance, de disponibilité et de complexité.


Shared-nothing vs shared-disk

Chevance (Serveurs multiprocesseurs, clusters et architectures parallèles) distingue deux grandes familles d'architectures de clusters.

Shared-nothing

Chaque nœud possédé son propre processeur, sa propre mémoire et son propre stockage. Les nœuds communiquent uniquement par messages réseau. Aucune ressource n'est partagee.

graph TB
    subgraph "Noeud 1"
        C1["CPU"] --> M1["RAM"]
        M1 --> D1["Disque"]
    end
    subgraph "Noeud 2"
        C2["CPU"] --> M2["RAM"]
        M2 --> D2["Disque"]
    end
    subgraph "Noeud 3"
        C3["CPU"] --> M3["RAM"]
        M3 --> D3["Disque"]
    end
    D1 --reseau--> D2
    D2 --reseau--> D3

Shared-disk

Tous les nœuds accedent a un stockage partage (SAN, NAS). Chaque nœud a son propre CPU et sa propre RAM, mais le disque est commun.

graph TB
    subgraph "Noeud A"
        CA["CPU"] --> MA["RAM"]
    end
    subgraph "Noeud B"
        CB["CPU"] --> MB["RAM"]
    end
    subgraph "Noeud C"
        CC["CPU"] --> MC["RAM"]
    end
    MA --> SAN["Stockage partage (SAN)"]
    MB --> SAN
    MC --> SAN

Comparaison

Critère Shared-nothing Shared-disk Hybride
Scalabilité Excellente (lineaire) Limitee par le stockage Variable
Complexité Partitionnement des données Gestion des locks distribués Les deux
Disponibilité Panne d'un nœud = perte partielle Panne stockage = panne totale Dépend
Exemples Cassandra, Kafka, CockroachDB Oracle RAC, GPFS Ceph, HDFS
Performance I/O Locale, rapide Réseau, plus lent Variable

Note

Le modèle shared-nothing domine le cloud moderne. Quand on deploie sur AWS, GCP ou Azure, chaque instance est indépendante par défaut — il n'y a pas de SAN partage. Les architectures cloud-native (microservices, bases distribuées) sont fondamentalement shared-nothing. Le shared-disk subsiste dans les environnements on-premise ou la cohérence forte est prioritaire (Oracle RAC pour les systèmes financiers).


Loi d'Amdahl

La loi d'Amdahl quantifie le speedup maximal d'un programme quand on ajoute des processeurs. Si une fraction s du programme est strictement séquentielle, le speedup maximal avec N processeurs est :

\[ \text{Speedup}(N) = \frac{1}{s + \frac{1 - s}{N}} \]

Quand N tend vers l'infini :

\[ \text{Speedup}_{\max} = \frac{1}{s} \]
Fraction séquentielle (s) Speedup max (N infini) Speedup avec 16 cœurs
1% 100x 14.4x
5% 20x 10.1x
10% 10x 6.4x
25% 4x 3.0x
50% 2x 1.9x

Warning

La loi d'Amdahl est impitoyable. Avec 10% de code séquentiel, on ne depassera jamais un speedup de 10x — même avec 1000 cœurs. Avant de scaler horizontalement, il faut mesurer la fraction séquentielle du système. Un lock global, une écriture synchrone en base, un appel API bloquant — tout cela contribue à la fraction séquentielle.

Ou se cache la fraction séquentielle

Dans un système réel, la fraction séquentielle n'est pas toujours evidente :

  • Serialisation/deserialisation : convertir des données entre formats prend du temps CPU séquentiel
  • Coordination distribuée : un consensus Raft ou Paxos serialise les écritures
  • Accès partage : une table de routage lue par tous les threads sous un read-lock
  • Garbage collection : les pauses GC "stop-the-world" sont séquentielles
  • Aggregation des résultats : un map-reduce doit fusionner les résultats partiels

Loi de Gustafson

La loi de Gustafson offre une perspective complementaire. Alors qu'Amdahl suppose un problème de taille fixe, Gustafson observe qu'en pratique, on augmente la taille du problème quand on dispose de plus de processeurs.

\[ \text{Speedup}(N) = N - s \times (N - 1) \]

Avec 10% de fraction séquentielle et 16 cœurs : Gustafson prédit un speedup de 14.5x (contre 6.4x pour Amdahl). La différence ? Amdahl mesure le temps pour un problème fixe. Gustafson mesure la taille du problème traitable en un temps fixe.

En pratique, les deux lois sont pertinentes :

  • Amdahl s'applique quand la latence compte (temps de réponse d'une requête)
  • Gustafson s'applique quand le throughput compte (volume de données traitees par heure)

Types de parallélisme

Parallélisme de données

Le même traitement est appliqué a des partitions différentes des données. C'est le modèle le plus courant et le plus facile à scaler.

Exemples : MapReduce, traitement d'images par blocs, calcul matriciel, sharding de base de données.

Parallélisme de tâches

Des traitements différents s'exécutent simultanément sur des données potentiellement différentes. Plus complexe à orchestrer.

Exemples : pipeline de microservices, stages d'un compilateur, producer/consumer.

Parallélisme de pipeline

Les données traversent une sequence d'étapes de traitement. Chaque étape travaille sur un élément différent. C'est l'équivalent logiciel du pipeline processeur.

Exemples : pipeline de streaming (Kafka Streams, Flink), pipeline CI/CD, traitement video en temps réel.


Haute disponibilité

Les clusters servent aussi la disponibilité — la capacité du système a rester opérationnel malgre les pannes.

Actif/passif

Un nœud est actif, l'autre est en standby. En cas de panne du nœud actif, le nœud passif prend le relais (failover). Le temps de basculement est typiquement de quelques secondes a quelques minutes.

graph LR
    CLIENT["Client"] --requetes--> ACTIF["Noeud actif"]
    ACTIF --heartbeat--> PASSIF["Noeud passif<br>(standby)"]
    ACTIF --replication--> PASSIF
  • Avantage : simple, le standby est une copie exacte
  • Inconvénient : la moitie des ressources est inutilisee en temps normal

Actif/actif

Tous les nœuds traitent du trafic simultanément. En cas de panne d'un nœud, les autres absorbent sa charge.

graph LR
    LB["Load balancer"] --requetes--> N1["Noeud 1"]
    LB --requetes--> N2["Noeud 2"]
    LB --requetes--> N3["Noeud 3"]
  • Avantage : toutes les ressources sont utilisées, meilleur rapport coût/capacité
  • Inconvénient : nécessité un mécanisme de partage ou de partitionnement des données

Métriques de disponibilité

Niveau Indisponibilite/an Commentaire
99% (deux 9) 3.65 jours Acceptable pour le dev
99.9% (trois 9) 8.76 heures Standard pour les applications internes
99.99% (quatre 9) 52.6 minutes Applications critiques
99.999% (cinq 9) 5.26 minutes Telecom, finance — actif/actif obligatoire

HPC : calcul haute performance

Les clusters HPC (High Performance Computing) sont conçus pour maximiser la puissance de calcul brute. Ils différent des clusters web/cloud par leur architecture et leurs contraintes.

MPI (Message Passing Interface)

MPI est le standard de communication pour le HPC. Chaque processus a sa propre mémoire ; les processus échangent des messages explicites. MPI fournit des primitives comme :

  • MPI_Send / MPI_Recv : communication point-à-point
  • MPI_Bcast : diffusion d'un processus vers tous
  • MPI_Reduce : aggregation (somme, max, etc.) de tous vers un

SLURM

SLURM (Simple Linux Utility for Resource Management) est l'ordonnanceur dominant en HPC. Il géré l'allocation des nœuds, la planification des jobs et la priorisation entre utilisateurs.

# Soumettre un job MPI sur 4 noeuds, 32 coeurs chacun
sbatch --nodes=4 --ntasks-per-node=32 --time=02:00:00 job.sh

Interconnects HPC

Le réseau est critique en HPC. Les interconnects specialises offrent des latences bien inférieures a Ethernet :

Technologie Latence Bande passante Usage
InfiniBand HDR ~1 us 200 Gbps HPC, AI training
InfiniBand NDR ~0.5 us 400 Gbps HPC, AI training
RoCE (RDMA over Ethernet) ~2-5 us 100-400 Gbps Cloud HPC
Ethernet 100G ~5-10 us 100 Gbps Cluster générique

Tip

L'entrainement de grands modèles d'IA (LLM) est aujourd'hui l'un des principaux moteurs d'investissement en clusters HPC. La communication entre GPU (via NVLink, InfiniBand) est souvent le goulot — pas la puissance de calcul brute. Concevoir un système d'entrainement distribué revient à minimiser la communication inter-nœuds, exactement comme le prédit la loi d'Amdahl.


Quorum et consensus

Les clusters à haute disponibilité reposent sur des mécanismes de quorum pour éviter le split-brain — la situation où deux partitions du cluster pensent chacune être le cluster actif et acceptent des écritures contradictoires.

Le quorum exige qu'une majorité de nœuds (N/2 + 1) soit d'accord avant de prendre une décision. Avec 3 nœuds, il faut l'accord de 2. Avec 5 nœuds, il faut l'accord de 3.

Nombre de nœuds Quorum Pannes tolerees
1 1 0
2 2 0 (inutile)
3 2 1
5 3 2
7 4 3

Warning

Un cluster a 2 nœuds ne toléré aucune panne par quorum — si un nœud tombe, l'autre n'a pas la majorité. C'est pourquoi les clusters utilisent un nombre impair de nœuds, ou ajoutent un "temoin" (witness) léger qui ne porte pas de données mais participe au vote.

Les protocoles de consensus distribué (Raft, Paxos, ZAB) formalisent ce mécanisme. Etcd, ZooKeeper et Consul implementent ces protocoles pour fournir un stockage de configuration cohérent aux clusters.


Implications pour l'architecte

  1. Shared-nothing par défaut : dans le cloud, partez du principe que chaque instance est indépendante. Concevez pour la partition des données, pas pour le partage

  2. Mesurer la fraction séquentielle : avant de scaler horizontalement, identifiez ce qui ne parallelise pas. Un lock global sur une base de données est l'équivalent d'une fraction séquentielle de 100%

  3. Actif/actif > actif/passif : pour les systèmes critiques, l'actif/actif utilisé mieux les ressources et offre un failover plus rapide — au prix d'une complexité de cohérence

  4. Le réseau est le nouveau bus : dans un cluster, le réseau joue le rôle du bus mémoire dans un multiprocesseur. Sa latence et sa bande passante conditionnent les performances exactement comme le bus SMP conditionne celles d'un multiprocesseur

  5. Nombre impair de nœuds : pour tout cluster base sur le quorum (etcd, ZooKeeper, Kafka controllers), deployez un nombre impair de nœuds. Trois nœuds tolèrent une panne, cinq tolèrent deux pannes


Chapitre suivant : Virtualisation et abstraction matérielle — hyperviseurs, conteneurs et overhead de l'abstraction.