Performance: Temps de réponse vs. Débit, par Cary Millsap

Cet article est la traduction d’un article de Cary Millsap publié sur son blog. L’article original en anglais est:Throughput versus Response Time. C’est un commentaire sur l’article de Doug Burns Time Matters: Throughput vs. Response Time. Cary Millsap est un spécialiste de la performance, du tuning Oracle et a beaucoup écrit sur les files d’attentes.

J’ai apprécié le post de Doug Burns Performance: Mesurer le temps de réponse ou le débit sur son blog. Si vous ne l’avez pas encore lu, vous devriez. L’article et les commentaires sont excellents.
La courbe de rendement (temps de réponse en fonction de la charge du système) fait un coude, au point où le temps de réponse, presque constant, devient tout d’un coup exponentiel lorsque le système atteint une certaine charge.

Exemple de courbe de rendement tiré de Optimizing Oracle performance
– En abscisse (ρ): la charge (ou utilisation),
– En ordonnée (R): le temps de réponse.
– Les 3 courbes correspondent à un degré de parallélisme de 1,2 et 8

Courbe charge/temps de réponse

Le ‘coude’ (‘knee‘), est le point correspondant à la charge pour laquelle le rapport temps de réponse / utilisation est minimal.
Il peut être déterminé aussi par la tangente à la courbe, passant par le point d’origine des axes.
Ce ‘coude’ se décale vers la droite lorsque le degré de parallélisme augmente.

Ce que Doug a observé, c’est le fait que ce coude est le point où le rapport temps de réponse/débit est minimal. C’est ce rapport qui est important ici. Ce n’est pas le point où le temps de réponse est le plus rapide. Parce ce que, comme Doug l’a fait remarquer, ce point serait là où il n’y a pas d’autre charge en dehors de la votre sur le système … ce qui est formidable pour vous, mais pas si bon pour les affaires.

Je voudrais insister sur quelques points.

Batch ou transactionnel.

Tout d’abord, les exigences de performance sont complètement différentes pour du batch (traitement par lots, de nuit, ‘offline‘,…) ou pour de l’interactif (IHM, GUI, ‘online‘, transactionnel,…), comme l’on noté plusieurs commentaires sur le post de Doug.
Pour les batch, les gens cherchent normalement à avoir le débit maximum(throughput).
Avec un programmes interactif, les individus se soucient surtout de leur propre temps de réponse, et non pas du débit global de l’ensemble des utilisateurs. Même si les managers de ces personnes, eux, vont se soucier du débit général. Les individus se préoccupent sans doute du débit du groupe aussi, mais pas au point de rester travailler plus tard quand leurs tâches individuelles s’exécutent si lentement qu’ils ne peuvent pas les achever au cours de la journée de travail.

Il n’y a pas que les exigences de performance qui sont différentes pour un batch, mais l’ordonnancement des batch va être différent aussi. Si vous êtes chanceux, vous pouvez planifier votre charge batch de manière déterministe. Par exemple, vous pouvez peut-être employer un Workload Manager qui alimente la charge du système au compte goutte, en maintenant l’utilisation du système à 100% tout en faisant en sorte que la file d’attente (runqueue) ne dépasse pas 1. Mais les charges du transactionnel (online) sont presque toujours non-déterministes , ce qui veut dire qu’on ne peut pas les planifier du tout. C’est pour cette raison que vous devez garder à portée de main une marge de ressource inutilisée. Parce que sinon la charge du système va dépasser le point où la courbe fait ce coude exponentiel. Et alors, même si l’augmentation de charge est microscopique, le temps de réponse utilisateur va augmenter exponentiellement, ce qui entraîne douleurs et de souffrances…

Le profiling.

Le deuxième point que je veux aborder, et qui à mon avis n’est souvent pas très bien compris: Il est essentiel, même lorsqu’on cherche à optimiser le débit, de s’interresser aux temps de réponses individuels, comme dans le profiling, en isolant une unité de tâche fonctionnelle particulière. Il y a de bonnes pratiques pour rendre une tâche plus rapide, et il y en a aussi de mauvaises.

  • Les bonne pratiques sont celles qui cherchent à éliminer de la tâche tout le travail inutile, sans que cela ne cause des effets secondaires négatifs sur les autres tâches (sur celles que vous n’êtes pas en train d’analyser aujourd’hui).
  • Les mauvaises pratiques, elles, vont dégrader accidentellement les performances des autres tâches, de celles que vous êtes en train d’analyser.

Si vous restez dans les bonnes pratiques, vous ne verrez pas l’effet ‘en dents de scie’ auquel on pense souvent lorsqu’on parle d’optimiser une tâche à la fois. Vous savez: l’idée qu’en améliorant une unité de tâche A, on va dégrader une autre unité de tâche B, et que lorsqu’on va faire le tuning de B, on va casser à nouveau ce qui a été fait sur A. Ces résultats en dents de scie vont arriver lorsqu’on essaie de résoudre des problèmes de performance en modifiant des paramètres systèmes qui ont une portée globale. Par contre, si l’on essaie d’éliminer le travail inutile, alors le bénéfice est partagé, parce qu’il va permettre aux tâches concurrentes de s’exécuter plus vite aussi, puisque la tâche que vous avez optimisé utilise maintenant moins de ressources. Cela va permettre à tout le reste d’accéder plus simplement, et à un moindre coût, aux ressources nécessaires, sans avoir à être en file d’attente (queue) pour les obtenir.

C’est là que les choses sérieuses commencent: lorsqu’on essaie de comprendre comment éliminer ce travail inutile.
Une grande partie des tâches que nous voyons peuvent souvent s’améliorer en changeant juste quelques lignes de code. Par exemple la requête qui ne consomme plus que 9098 latches au lieu de 2142103, des choses comme ça (référence à cet article en anglais).
Et beaucoup d’autres tâches s’améliorent simplement en faisant une collecte de statistiques (analyze ou plutôt dbms_stats) correcte (référence à cet article de Karen Morton en anglais).
D’autres fois cela nécessite un ajustement de la stratégie d’indexation, ce qui peut paraître complexe lorsque vous avez besoin d’optimiser un tout un ensemble de requêtes SQL (c’est là qu’il y a une possibilité de dents de scie). Mais même cela est plus ou moins un problème résolu si vous comprenez le travail de Tapio Lahdenmäki

Mais revenons à l’idée de départ de l’article de Doug: je trouve tout a fait normal de vouloir optimiser à la fois le débit (throughput) et temps de réponse. C’est la maîtrise d’ouvrage, le métier, doit décider du bon compromis. Et je suis persuadé que si vous voulez avoir un quelconque espoir d’optimiser quoi que ce soit (temps de réponse ou débit), il est essentiel de se concentrer sur cette élimination du travail inutile, individuellement pour chacune des tâches qui tournent en parallèle.

On peut voir cela de la manière suivante. Une tâche ne peut fonctionner à sa vitesse optimale que si elle est efficace. Vous ne pouvez pas savoir si une tâche est efficace sans avoir mesuré sa durée. Et je veux dire avoir mesuré la durée de cette tâche précisément, pas seulement une partie de cette tâche, ni l’ensemble de cette tâche avec d’autres autour d’elle. C’est cela le profiling: la mesure d’une tâche précise, afin de déterminer exactement où elle passe son temps, et donc de savoir si cette tâche dépense efficacement le temps système et les ressources qu’elle utilise.

Vous pouvez améliorer un système sans profiling, et même peut-être le rendre optimal. Mais sans savoir si ses tâches sont efficaces, vous ne saurez jamais si le système est optimal. Et sans faire du profiling, vous ne saurez pas si une tâche donnée est efficace. Et dans ce cas, vous perdez du temps et d’argent. C’est pourquoi j’insiste sur le fait que le profiling d’une tâche individuelle est absolument indispensable à quiconque veut optimiser les performances.


Optimizing Oracle Performance
Par Cary Millsap et Jeff Holt


Plusieurs points évoqués ici sont détaillés dans ce livre:
Courbe de rendement, profiling, théorie des files d’attentes,…

Laisser un commentaire