Trouvez le goulot d'étranglement
L’an dernier, 152 personnes naviguaient en même temps sur la billetterie au pic d’ouverture. Cette année, l’équipe marketing en annonce 400. Le site tiendra-t-il ? Et s’il ne tient pas, faut-il acheter un processeur plus rapide, un meilleur disque, ou un deuxième serveur web ?
Vous allez voir qu’avec les trois demandes de service calculées au chapitre précédent, et rien d’autre, on peut déjà répondre à ces questions à la main. C’est toute la puissance des bornes asymptotiques.
Le goulot : la ressource qui sature la première
Section intitulée « Le goulot : la ressource qui sature la première »Reprenons la loi de la demande de service, écrite à l’envers : . Quand le débit du système augmente, l’utilisation de toutes les ressources augmente, chacune proportionnellement à sa demande. Or une utilisation ne peut pas dépasser 1 : une ressource ne peut pas être occupée plus de 100 % du temps. Donc, pour chaque ressource, , et la contrainte la plus forte vient de la ressource de plus grande demande :
où est la plus grande demande de service. Cette ressource s’appelle le goulot d’étranglement (bottleneck) : c’est elle qui atteint 100 % d’utilisation la première, et elle fixe le débit maximal du système entier.
Remarquez que le goulot n’est pas forcément la ressource la plus lente par visite. Le processeur fait 5 visites de 6 ms, le disque 4 visites de 15 ms : c’est le produit qui compte.
Les bornes asymptotiques
Section intitulée « Les bornes asymptotiques »Considérons un système fermé : utilisateurs, chacun avec un temps de réflexion , et ressources de demandes . Notons la demande totale, c’est-à-dire le temps de réponse d’une requête qui ne rencontrerait aucune file d’attente.
Borne sur le débit
Section intitulée « Borne sur le débit »Deux contraintes limitent le débit :
- Peu d’utilisateurs : même sans aucune attente, un utilisateur ne peut pas envoyer plus d’une requête toutes les secondes. Avec utilisateurs, .
- Beaucoup d’utilisateurs : le goulot impose .
Borne sur le temps de réponse
Section intitulée « Borne sur le temps de réponse »De même, le temps de réponse est minoré de deux façons :
- une requête doit au minimum recevoir son service : ;
- avec la loi du temps de réponse interactif, , et comme , on obtient .
Le point de saturation
Section intitulée « Le point de saturation »Les deux droites de la borne sur le débit se croisent en :
C’est le point de saturation. En dessous de , le système peut en théorie servir tout le monde sans attente, et le débit croît avec . Au-delà, le goulot est saturé : ajouter des utilisateurs n’augmente plus le débit, mais seulement le temps de réponse, qui croît alors de par utilisateur supplémentaire.
Le graphique ci-dessous montre les deux bornes du débit (en pointillés) et, en trait plein, le débit exact que calculera l’algorithme MVA au chapitre 5. La vraie courbe reste sous les bornes et s’en éloigne surtout autour de , là où les files d’attente se forment.
Quelle amélioration vaut la peine ?
Section intitulée « Quelle amélioration vaut la peine ? »Les bornes donnent une règle de décision très simple. Seule la réduction de relève le plafond de débit. Améliorer une autre ressource réduit un peu (donc le temps de réponse à faible charge) mais ne change rien au débit maximal.
Comparons trois investissements pour la billetterie :
| Amélioration | Nouvelles demandes (web, CPU, disque) | ||
|---|---|---|---|
| Aucune | 20, 30, 60 ms | 16,7 req/s | 252 |
| Serveur web deux fois plus rapide | 10, 30, 60 ms | 16,7 req/s | 252 |
| Processeur deux fois plus rapide | 20, 15, 60 ms | 16,7 req/s | 252 |
| Disque SSD deux fois plus rapide | 20, 30, 30 ms | 33,3 req/s | 503 |
Seul le disque fait bouger les choses, et il double le débit maximal. Mais attention : avec un disque à 30 ms, le processeur (30 ms aussi) devient co-goulot. Pour aller plus loin, il faudra améliorer les deux. C’est le phénomène du goulot qui se déplace : on n’en a jamais fini, on repousse simplement la limite jusqu’à la ressource suivante.
Et avec le SSD, les 400 utilisateurs de cette année passent-ils ? : oui, en théorie on reste sous la saturation. La borne vaut 0,08 s, ce qui est encourageant, mais une borne reste optimiste : le chapitre 5 donnera le vrai temps de réponse.
def bornes(D, Z, N): """Bornes asymptotiques d'un système fermé : N utilisateurs, temps de réflexion Z.""" D_tot, D_max = sum(D.values()), max(D.values()) goulot = max(D, key=D.get) X_max = min(N / (D_tot + Z), 1 / D_max) R_min = max(D_tot, N * D_max - Z) N_sat = (D_tot + Z) / D_max return goulot, X_max, R_min, N_sat
D = {"web": 0.020, "cpu": 0.030, "disque": 0.060} # demandes de service (s)for N in (152, 400): goulot, X, R, N_sat = bornes(D, Z=15, N=N) print(f"N={N}: goulot={goulot}, X <= {X:.1f} req/s, R >= {R:.2f} s, N* = {N_sat:.0f}")En résumé
Section intitulée « En résumé »- Comme , le débit est plafonné par la ressource de plus grande demande : . C’est le goulot.
- Borne sur le débit d’un système fermé : .
- Borne sur le temps de réponse : .
- Le point de saturation sépare le régime où le débit croît de celui où seul le temps de réponse augmente.
- Seule la réduction de relève le plafond ; après amélioration, le goulot se déplace.
- Les bornes sont optimistes : elles ignorent les files d’attente, que les chapitres 4 et 5 prennent en compte.
Exercices
Section intitulée « Exercices »Exercice · Trouver le goulot
facileUn serveur d’analyse de données traite 20 tâches par seconde. On mesure les utilisations suivantes : processeur 0,5, disque A 0,7, disque B 0,3, réseau 0,2.
- Calculez la demande de service de chaque ressource.
- Quel est le goulot, et quel est le débit maximal ?
Voir la solution
- Par la loi de la demande de service, : processeur ms, disque A ms, disque B ms, réseau ms.
- Le goulot est le disque A (35 ms). Le débit maximal vaut tâches/s. On pouvait le voir directement : c’est la ressource la plus utilisée, et elle atteindra 100 % quand le débit sera multiplié par .
En code
X0 = 20 # tâches/sU = {"processeur": 0.5, "disque A": 0.7, "disque B": 0.3, "réseau": 0.2}
D = {nom: u / X0 for nom, u in U.items()} # loi de la demande de servicefor nom, d in D.items(): print(f"{nom:<10} D = {d * 1000:.0f} ms") # 25, 35, 15, 10 msgoulot = max(D, key=D.get)print(goulot, round(1 / D[goulot], 1)) # disque A 28.6 tâches/sX0 <- 20 # tâches/sU <- c(processeur = 0.5, disque_A = 0.7, disque_B = 0.3, reseau = 0.2)
D <- U / X0 # loi de la demande de serviceD * 1000 # 25 35 15 10 msgoulot <- names(which.max(D))c(goulot, round(1 / max(D), 1)) # "disque_A" "28.6"Exercice · Bornes d'un système interactif
moyenUn intranet a trois ressources de demandes ms, ms et ms. Les employés réfléchissent en moyenne s entre deux requêtes.
- Calculez le point de saturation .
- Donnez les bornes sur le débit et sur le temps de réponse pour 50 puis 200 employés.
Voir la solution
s et s (le disque).
- , soit environ 102 employés.
- Pour : req/s et s. Pour : req/s et s. Avec 200 employés, le système est largement saturé : au moins 10 s par requête.
En code
D = {"cpu": 0.040, "disque": 0.100, "réseau": 0.020} # demandes de service (s)Z = 10 # temps de réflexion (s)D_tot, D_max = sum(D.values()), max(D.values())
N_sat = (D_tot + Z) / D_max # point de saturationprint(f"N* = {N_sat:.1f}") # N* = 101.6for N in (50, 200): X_borne = min(N / (D_tot + Z), 1 / D_max) # borne sur le débit R_borne = max(D_tot, N * D_max - Z) # borne sur le temps de réponse print(f"N = {N}: X <= {X_borne:.2f} req/s, R >= {R_borne:.2f} s")# N = 50: X <= 4.92 req/s, R >= 0.16 s# N = 200: X <= 10.00 req/s, R >= 10.00 sD <- c(cpu = 0.040, disque = 0.100, reseau = 0.020) # demandes de service (s)Z <- 10 # temps de réflexion (s)D_tot <- sum(D); D_max <- max(D)
(D_tot + Z) / D_max # N* = 101.6for (N in c(50, 200)) { X_borne <- min(N / (D_tot + Z), 1 / D_max) # borne sur le débit R_borne <- max(D_tot, N * D_max - Z) # borne sur le temps de réponse cat(sprintf("N = %d : X <= %.2f req/s, R >= %.2f s\n", N, X_borne, R_borne))}# N = 50 : X <= 4.92 req/s, R >= 0.16 s# N = 200 : X <= 10.00 req/s, R >= 10.00 sExercice · Dimensionner un achat
difficileReprenez l’intranet de l’exercice précédent. L’entreprise veut que 200 employés aient un temps de réponse borné inférieurement par moins de 1 s (c’est une condition nécessaire, pas suffisante). Deux options : un disque deux fois plus rapide, ou deux disques identiques à l’actuel entre lesquels on répartit équitablement les données.
- Calculez et la borne sur pour 200 employés dans chaque cas.
- Laquelle choisir ?
Voir la solution
- Disque deux fois plus rapide : ms. Le nouveau goulot est le disque à 50 ms (le processeur est à 40 ms). s, . Pour 200 employés, s. Deux disques : chacun reçoit la moitié des accès, donc ms par disque. Les demandes sont 40, 50, 50 et 20 ms, s, s, . Pour 200 employés, s.
- Les deux options donnent le même plafond de débit (20 req/s) et une borne sur bien inférieure à 1 s. Mais dans les deux cas, 200 employés sont juste sous le point de saturation : les files d’attente seront importantes et le vrai temps de réponse bien supérieur à la borne. Il faudrait aussi traiter le processeur, qui devient presque un co-goulot, ou vérifier avec MVA (chapitre 5). La leçon : la borne est une condition nécessaire, et un système dimensionné pile à est un système qui souffrira.
En code
Z, N = 10, 200options = { "disque x2": [0.040, 0.050, 0.020], # CPU, disque, réseau (s) "deux disques": [0.040, 0.050, 0.050, 0.020], # CPU, disque 1, disque 2, réseau}for nom, D in options.items(): D_tot, D_max = sum(D), max(D) N_sat = (D_tot + Z) / D_max R_borne = max(D_tot, N * D_max - Z) print(f"{nom:<13} N* = {N_sat:.0f}, X_max = {1 / D_max:.0f} req/s, R >= {R_borne:.2f} s")# disque x2 N* = 202, X_max = 20 req/s, R >= 0.11 s# deux disques N* = 203, X_max = 20 req/s, R >= 0.16 sZ <- 10; N <- 200options <- list( "disque x2" = c(0.040, 0.050, 0.020), # CPU, disque, réseau (s) "deux disques" = c(0.040, 0.050, 0.050, 0.020) # CPU, disque 1, disque 2, réseau)for (nom in names(options)) { D <- options[[nom]] N_sat <- (sum(D) + Z) / max(D) R_borne <- max(sum(D), N * max(D) - Z) cat(sprintf("%-13s N* = %.0f, X_max = %.0f req/s, R >= %.2f s\n", nom, N_sat, 1 / max(D), R_borne))}# disque x2 N* = 202, X_max = 20 req/s, R >= 0.11 s# deux disques N* = 203, X_max = 20 req/s, R >= 0.16 s