Modèle de charge ouvert ou fermé : lequel choisir ?
7 min de lecture
Choisir un modèle de charge ouvert ou fermé dépend surtout de la façon dont les utilisateurs atteignent votre système. Prenez le modèle ouvert, qui démarre de nouvelles itérations à un taux d’arrivée fixé, pour les sites et API publics où les utilisateurs continuent d’arriver même quand vous ralentissez, et le modèle fermé, un nombre fixe d’utilisateurs virtuels qui attendent chacun la fin de leur itération précédente, seulement là où le système plafonne lui-même la concurrence. Le choix pèse surtout en saturation, quand un test fermé freine sa propre charge et fait paraître le système plus sain qu’il ne l’est.
Les faits sur les outils viennent de la documentation de chaque projet, vérifiée le 9 octobre 2026.
| Modèle ouvert | Modèle fermé | |
|---|---|---|
| Vous fixez | Nouvelles itérations ou nouveaux utilisateurs par seconde | Utilisateurs virtuels simultanés |
| Quand les réponses ralentissent | Le travail continue d’arriver, les files d’attente grossissent | Les utilisateurs attendent, la charge envoyée baisse |
| Systèmes réels de ce type | La plupart des sites et API publics | Centres d’appels, files de billetterie, pools de workers |
| k6 | constant-arrival-rate, ramping-arrival-rate | constant-vus, ramping-vus |
| Gatling | injectOpen | injectClosed |
| Locust | Approché avec constant_throughput ou poisson | Utilisateurs avec un wait_time |
| JMeter | Open Model Thread Group, plugin Arrivals | Thread Group |
Quelle est la différence entre un modèle de charge ouvert et un modèle fermé ?
Dans un modèle ouvert, c’est le générateur de charge qui décide quand le travail arrive, et dans un modèle fermé, c’est le temps de réponse du système.
La documentation de k6 le dit clairement : dans le modèle fermé, l’itération suivante d’un utilisateur virtuel ne démarre qu’une fois la précédente terminée, alors que dans le modèle ouvert les nouvelles itérations arrivent indépendamment de la fin des précédentes (vérifié le 9 octobre 2026). Un test fermé avec 50 utilisateurs virtuels n’a jamais plus de 50 itérations en cours. Un test ouvert à 50 itérations par seconde en lance 50 de plus chaque seconde, et si chacune dure plus longtemps, davantage se chevauchent.
Pourquoi un modèle fermé masque-t-il la latence quand le système sature ?
Parce que le test ralentit en même temps que le système. Quand les réponses prennent plus de temps, chaque utilisateur d’un modèle fermé envoie moins de requêtes, et la charge baisse au moment précis où vous vouliez la voir monter.
La documentation de k6 décrit l’effet : des réponses plus lentes allongent les itérations et réduisent le taux d’arrivée des nouvelles. La page de Gatling sur les modèles de charge va plus loin et qualifie de test cassé, qui vérifie un comportement imaginaire, un modèle fermé appliqué à un système en réalité ouvert (vérifié le 9 octobre 2026).
Un test fermé montre donc des temps de réponse qui plafonnent, car il ne peut jamais y avoir plus de requêtes en cours que d’utilisateurs. Un test ouvert montre la file qui grossit, avec des temps de réponse qui montent tant que les arrivées dépassent ce que le système traite. C’est cette seconde image que vos utilisateurs verraient, et les temps de réponse p95 et p99 que vous lisez à la fin ne valent que ce que vaut le modèle de charge qui les a produits.
La documentation de k6 note qu’une partie de la littérature sur les tests appelle ce problème coordinated omission. Un article USENIX de 2006 cité par la documentation de Gatling, Open Versus Closed: A Cautionary Tale, conclut que les deux modèles donnent des résultats nettement différents, même avec la même charge et les mêmes demandes de service.
Quel modèle correspond à votre trafic réel ?
Prenez un modèle ouvert pour tout ce que le public peut atteindre, et un modèle fermé seulement là où le système limite lui-même le nombre d’utilisateurs actifs en même temps.
La documentation de Gatling cite comme systèmes fermés les centres d’appels où tous les opérateurs sont occupés et les sites de billetterie qui placent les utilisateurs dans une file d’attente à pleine capacité, et indique que la plupart des sites web se comportent comme des systèmes ouverts. Un traitement par lots avec un nombre fixe de workers, ou un consommateur de file à concurrence fixée, est fermé lui aussi. Les API publiques, les pages web et les webhooks sont ouverts : rien ne retient la requête suivante parce que la précédente a été lente.
Beaucoup de systèmes se situent entre les deux : une cliente arrive à son propre rythme, puis attend chaque page pendant sa visite. L’article cité plus haut parle de modèle partiellement ouvert. Dans k6 ou Gatling, fixez le taux d’arrivée des sessions et faites de chaque itération un parcours utilisateur complet, avec ses propres pauses.
Comment régler chaque modèle dans k6 ?
Par l’executor. constant-vus et ramping-vus donnent un modèle fermé, constant-arrival-rate et ramping-arrival-rate un modèle ouvert.
Un scénario fermé définit executor: "constant-vus" avec un nombre de vus et une duration. Un scénario ouvert fixe plutôt un taux, et vous préallouez assez d’utilisateurs virtuels pour le tenir :
export const options = {
scenarios: {
open_model: {
executor: "constant-arrival-rate",
rate: 50,
timeUnit: "1s",
duration: "5m",
preAllocatedVUs: 100,
},
},
thresholds: {
dropped_iterations: ["count<10"],
},
};
k6 ne démarre une itération que s’il dispose d’un utilisateur virtuel libre, et sa documentation déconseille de compter sur maxVUs, car ajouter des utilisateurs en cours de test peut surcharger le générateur de charge. Quand aucun utilisateur n’est libre, k6 enregistre une itération abandonnée, ce qui, tard dans un test, signifie souvent que le système ralentit. Le seuil ci-dessus fait échouer l’exécution à partir de dix. Ne mettez pas de sleep() à la fin d’une itération à taux d’arrivée, puisque l’executor cadence déjà les démarrages (vérifié le 9 octobre 2026).
Si vous exécutez des scripts k6 sur LoadFocus, son exécution k6 dans le cloud prend la charge dans les réglages du test, et son validateur de script prévient que les scénarios à taux d’arrivée y tournent avec un nombre fixe d’utilisateurs, si bien que le débit de requêtes n’est pas maintenu. Pour un vrai test en modèle ouvert, lancez les executors à taux d’arrivée avec k6 lui-même, ou sur un service qui les exécute tels qu’ils sont écrits.
Comment Gatling, Locust et JMeter expriment-ils chaque modèle ?
Gatling sépare les deux modèles dans son API, JMeter propose les deux à travers des thread groups différents, et Locust est construit autour d’un nombre fixe d’utilisateurs.
Gatling. Un scénario utilise soit injectOpen, soit injectClosed. Les étapes ouvertes comme constantUsersPerSec et rampUsersPerSec fixent des taux d’arrivée, les étapes fermées comme constantConcurrentUsers et rampConcurrentUsers fixent la concurrence. Un même profil d’injection ne peut pas mélanger les deux (vérifié le 9 octobre 2026).
Locust. Vous fixez un nombre d’utilisateurs, et le wait_time de chaque utilisateur règle la pause entre les tâches. constant_throughput et constant_pacing ajustent cette pause pour que chaque utilisateur exécute au plus un nombre donné de tâches par seconde, mais la documentation précise que le temps d’attente ne peut que limiter le débit et ne lance pas de nouveaux utilisateurs pour atteindre une cible. poisson() tire des pauses aléatoires, que la documentation juge plus proches des arrivées réelles. L’exemple de la documentation pour 500 itérations de tâche par seconde est constant_throughput(0.1) avec 5 000 utilisateurs, un pool fermé avec beaucoup de marge (vérifié le 9 octobre 2026).
JMeter. Le Thread Group classique est un pool fermé de threads. Les timers Constant Throughput et Precise Throughput cadencent ce pool vers un taux cible, et la référence prévient que le débit baisse si le serveur ne suit pas ou s’il n’y a pas assez de threads. Pour les arrivées, JMeter 5.5 a ajouté l’Open Model Thread Group, toujours marqué comme expérimental, avec des plannings comme rate(10/sec) random_arrivals(1 min). Le plugin communautaire Arrivals Thread Group démarre de nouveaux threads quand tous les threads existants sont occupés, avec une limite de concurrence comme soupape de sécurité (vérifié le 9 octobre 2026).
Que surveiller pendant un test en modèle ouvert ?
Surveillez le générateur de charge d’aussi près que le système testé. En modèle ouvert, un système lent signifie plus d’utilisateurs simultanés de votre côté, et ils coûtent de la mémoire et du CPU.
Fixez un plafond, par exemple maxVUs dans k6 ou la limite de concurrence du plugin JMeter, et considérez le fait de l’atteindre comme un résultat : le système n’a pas pu absorber le taux demandé.
FAQ
Un modèle de charge fermé est-il parfois le bon choix ? Oui. Utilisez-le quand le système réel plafonne la concurrence, par exemple avec un pool fixe de workers, un consommateur de file ou un centre d’appels, ou quand vous voulez savoir combien de sessions simultanées un composant supporte. Pour le trafic web public, un modèle ouvert convient mieux.
Ajouter du temps de réflexion transforme-t-il un modèle fermé en modèle ouvert ? Non. Le temps de réflexion réduit la fréquence des requêtes de chaque utilisateur, mais chaque utilisateur attend toujours la réponse précédente, donc un système lent freine quand même le test. Seul un taux d’arrivée fixé indépendamment des temps de réponse donne un modèle ouvert.
Combien d’utilisateurs virtuels faut-il pour un test à taux d’arrivée ? Assez pour couvrir toutes les itérations en cours au même moment. La documentation de k6 suggère la durée médiane d’une itération multipliée par le taux cible, plus une marge pour la variabilité, à trouver par de courts essais avant le test complet.
À lire aussi
- Coordinated omission : ce que c’est et comment l’éviter
- Loi de Little en test de charge : dimensionner et vérifier
- Temps de réflexion en test de charge : bien le régler
- Débit vs latence : comment ils interagissent sous charge
- Loi d’Amdahl : formule, exemples et limites
- Théorie des files d’attente : ce qu’elle dit de la latence
Les affirmations techniques de cet article n'ont pas été relues de façon indépendante.