Quand des gains de performance impressionnants ne comptent pas
(blog.colinbreck.com)- L’optimisation des performances est un puissant moyen de comprendre des systèmes complexes et d’améliorer un produit, mais même un résultat 10 fois plus rapide peut ne pas changer les méthodes de travail réelles ni le débit
- Même si l’on réduit le temps de réponse d’une requête de 5 à 10 minutes à 30 secondes à 1 minute, l’effet perçu reste limité dès lors qu’on dépasse le seuil d’environ 10 secondes au-delà duquel une personne cesse d’attendre en restant attentive
- Lorsque le travail est regroupé en unités entières, comme 1 ou 2 tâches par jour, une amélioration de 25 à 50 % ne suffit pas ; déplacement compris, chaque tâche doit prendre 4 heures ou moins pour qu’il soit possible d’en réaliser 2 par jour
- Dans les pipelines de données, une étape lente exerce une backpressure sur l’amont ; ainsi, même si une étape isolée devient beaucoup plus rapide, le débit de bout en bout peut ne pas augmenter tant que tous les goulots d’étranglement ne sont pas levés
- Les améliorations de performance doivent être évaluées non pas à l’aune de benchmarks isolés, mais des résultats recherchés ; si elles ne franchissent pas des contraintes comme le maintien de l’attention, l’augmentation des unités de travail ou le débit global, même de gros progrès peuvent avoir peu d’effet concret
Pourquoi les chiffres de performance et les résultats réels divergent
- Le travail sur les performances est gratifiant, car il peut rendre les systèmes plus efficaces et ouvrir de nouvelles possibilités aux clients
- Il aide aussi à acquérir une compréhension empirique de la manière dont des systèmes complexes interagissent à grande échelle et sous charge
- En travaillant au plus près du système, des idées d’amélioration du produit et du service émergent, dont certaines ne sont pas directement liées à l’optimisation des performances
- Cependant, même des résultats séduisants comme « 10 fois plus rapide » ou « 50 % de ressources en moins » peuvent avoir du mal à produire le changement attendu s’ils ne franchissent pas des contraintes cachées
Au-delà de 10 secondes, l’attention de l’utilisateur décroche
- Un exemple concerne l’amélioration des performances de requêtes dans une nouvelle base de données : les requêtes les plus coûteuses, qui prenaient 5 à 10 minutes dans l’ancienne base, ont été ramenées à 30 secondes à 1 minute
- Ce résultat représentait une amélioration d’un ordre de grandeur, mais il fallait encore une autre amélioration majeure pour transformer l’expérience utilisateur
- Les recherches en interaction humain-machine situent à environ 10 secondes la limite de maintien de l’attention d’une personne sur l’ensemble d’une tâche
- 0,1 seconde est le seuil perçu comme un retour immédiat
- Environ 1 seconde est le seuil à partir duquel le flux de travail reste continu
- Environ 10 secondes est le seuil de maintien de l’attention sur l’ensemble de la tâche
- Des retours comme un indicateur de progression ou une estimation du temps restant peuvent aider à maintenir l’attention
- 30 secondes comme 5 minutes dépassent les 10 secondes ; l’utilisateur va donc consulter ses messages, aller prendre un café, engager une conversation ou basculer vers une autre tâche
- Si l’interface est déjà chargée lorsque l’utilisateur revient quelques minutes ou quelques heures plus tard, le fait que l’attente réelle ait été de 30 secondes ou de 5 minutes ne change pas grand-chose à sa manière de travailler
- Dans ce projet, de nombreuses requêtes ont finalement été ramenées à 10 secondes ou moins, et certaines requêtes auparavant impossibles à cause de timeouts sont devenues réalisables
- Outre la latence des requêtes de données, la latence des requêtes de métadonnées et le temps de rendu des pages web ont aussi joué un rôle important dans l’amélioration globale des performances
- L’IO asynchrone et l’amélioration de l’agrégation des données laissent encore entrevoir une nouvelle amélioration d’un ordre de grandeur ; dans ce cas, des requêtes qui prenaient autrefois plusieurs minutes pourraient s’exécuter en moins d’une seconde
Le seuil qui fait passer de 1 à 2 tâches par jour
- Dans un projet, l’automatisation de tâches manuelles, la suppression d’étapes inutiles, une certaine parallélisation et le report à plus tard d’étapes pouvant être traitées de manière asynchrone ont permis de ramener l’ensemble du processus de plusieurs heures à moins d’une heure de façon fiable
- L’amélioration était d’environ 25 à 50 %, mais le processus global n’a pas changé à cause de contraintes logistiques
- On peut penser à des cas comme un plombier, un électricien ou un menuisier qui doit réserver un créneau sur site, se déplacer, puis terminer le travail
- Si la journée de travail dure 8 heures et qu’une intervention sur un site prend 8 heures, économiser 2 ou 3 heures ne laisse pas le temps de se rendre sur un nouveau site et d’y terminer une nouvelle tâche
- Tant que chaque tâche, déplacement compris, ne dure pas 4 heures ou moins, il est impossible d’en terminer 2 dans la journée
- Tant que ce seuil n’est pas franchi, les gains d’efficacité dans les étapes intermédiaires ne se traduisent pas par une hausse de la production
- Le fait de se concentrer sur les performances peut aussi permettre des améliorations de qualité et de fiabilité qui ont un impact direct sur l’expérience client
- Même de petites améliorations de performance qui ne constituent pas une percée en production peuvent accélérer les itérations dans les environnements de test, rendant le développement de fonctionnalités et la résolution de défauts plus rapides
Les goulots d’étranglement dans un pipeline avec backpressure
- Beaucoup d’infrastructures logicielles métier comprennent des pipelines de données qui traitent des événements issus de sources diverses : véhicules, équipements industriels, téléphones mobiles ou transactions financières
- Les événements sont généralement stockés dans un journal durable, puis consommés et traités par des services en aval
- Pour atteindre un débit élevé à grande échelle, le journal doit être partitionné, et les services en aval utilisent des techniques comme le traitement par lots, le pipelining, le parallélisme, l’allocation mémoire efficace ou le scaling dynamique
- Les goulots d’étranglement dans les pipelines de données sont difficiles à identifier, car les comportements du système sont interdépendants
- Une étape lente exerce délibérément une backpressure sur les étapes en amont
- S’il existe plusieurs goulots d’étranglement, le débit global n’augmente pas tant que le dernier d’entre eux n’a pas été supprimé
- Découper le pipeline en étapes et comprendre les caractéristiques de performance et les limites de chacune constitue une bonne pratique d’ingénierie
- Mais même améliorer une seule étape de plusieurs ordres de grandeur peut n’avoir aucun effet sur le débit global
- Pour améliorer le débit, le chiffre important n’est pas le benchmark d’une étape isolée, mais le débit de bout en bout
Une approche empirique pour trouver les goulots d’étranglement
- Pour comprendre la dynamique et les goulots d’étranglement de tels systèmes, il est utile de procéder empiriquement à partir du début du pipeline
- Par exemple, on peut commencer par l’étape qui lit les événements depuis un journal distribué et les jette
- Si cette seule étape n’atteint pas le débit cible, optimiser les étapes en aval est une perte de temps
- Les benchmarks en aval, comme le nombre de lignes par seconde qu’une base de données peut insérer, peuvent aussi être importants, mais l’analyse doit commencer par l’amont
- La simulation est également une méthode utile pour comprendre les systèmes complexes et leurs performances
Le critère d’une amélioration des performances, ce sont les résultats visés
- Le travail sur les performances est difficile, mais c’est aussi un entraînement pour comprendre en profondeur des systèmes complexes et créer de meilleurs produits
- Si l’on doit retenir l’attention d’une personne, il faut répondre en environ 10 secondes
- Si l’unité de travail globale est la contrainte, une amélioration en pourcentage ne suffit pas : il faut permettre de passer de 1 à 2 tâches par jour
- Pour maximiser le débit d’un pipeline avec backpressure, il faut souvent résoudre tous les goulots d’étranglement, pas seulement un ou deux
- Si ces contraintes ne sont pas franchies, même une amélioration des performances d’un ordre de grandeur peut ne pas produire le résultat recherché
1 commentaires
Commentaires de Lobste.rs
Si l’on est déçu après avoir amélioré de plusieurs dizaines de fois une étape qui n’a aucun effet sur le débit global, c’est l’occasion de rappeler la loi d’Amdahl
J’en entends sans cesse de nouvelles, puis je les oublie parce qu’elles sont trop spécialisées pour être souvent utilisées. Cela ne veut pas dire pour autant qu’elles ne sont pas valides ou utiles comme savoir transmis entre générations
Je me demande surtout pourquoi on cherchait à optimiser une partie qui ne représentait au départ qu’un tout petit fragment du temps total
Je ne sais pas si les indications étaient mauvaises ou si les outils de performance étaient insuffisants. Il est rare que quelqu’un choisisse délibérément de travailler sur quelque chose qui a très peu d’impact ; en général, il y a un problème plus profond derrière
On examine un problème, un échantillonnage fait ressortir une fonction précise, et en regardant vite fait on se dit qu’on pourrait sans doute améliorer l’implémentation assez facilement. Mais on est occupé à autre chose, donc on se dit « je m’en occuperai plus tard »
Plus tard, on se souvient de cette amélioration facile et on s’y met, sauf qu’en pratique la modification est plus complexe que prévu. Pourtant une vision en tunnel s’installe, on veut résoudre le puzzle, et on y consacre beaucoup de temps
En réalité, le problème de performance était mineur. Il paraissait important en proportion dans le contexte observé à ce moment-là, ou bien le temps absolu n’avait guère d’importance, ou alors le blocage venait des entrées/sorties plutôt que du CPU. C’est une forme de nerd sniping auto-infligé
Il a quand même ignoré cet avertissement et poursuivi l’optimisation, puis a été surpris de constater une amélioration globale inférieure à 0,1 %. Avec un peu de connaissance du domaine, on voyait déjà intuitivement que ce n’était pas une partie coûteuse, mais on l’a même aidé à mesurer le coût réel en performance pour éviter de lui faire perdre du temps
Ou bien un benchmark a pu induire en erreur. Tous les systèmes ne montrent pas facilement le coût de toutes les méthodes ou de tous les processus en conditions réelles
Ces explications relèvent toutes, à des degrés divers, d’un dysfonctionnement ; certaines tiennent davantage à l’individu, d’autres davantage à l’environnement
3.1. Si l’on travaille chez un hyperscaler, économiser 0,1 % de calcul peut avoir un effet économique suffisant pour payer une maison en bord de mer, même si cela reste totalement invisible pour les utilisateurs
Il arrive souvent que les pratiques de programmation courantes soient globalement lentes. Je pense par exemple à du code orienté objet rempli de pointeurs et d’allocations sur le tas via un allocateur générique. Où que l’on touche, cela ne représente qu’un petit morceau du temps total ; dans le pire des cas, il n’y a pas de solution en dehors d’une réécriture complète. Avec un peu de chance, on peut la faire progressivement
Même s’il n’y a que deux goulots d’étranglement, s’ils sont dans le même ordre de grandeur à un facteur d’un seul chiffre près, éliminer parfaitement le pire d’entre eux ne donnera même pas un gain d’un ordre de grandeur à un seul chiffre. Souvent, comme le dit l’article, il faut franchir un seuil bien plus élevé pour obtenir un bénéfice réellement significatif
Et puis un ordinateur ressemble davantage à un système distribué qui fonctionne en parallèle : quelques CPU, un GPU, des disques, de l’Ethernet, etc., et la vitesse du processus est limitée par l’étape la plus lente du pipeline. Si l’on corrige cette étape, c’est la suivante qui devient limitante ; dans le pire des cas, il y a plusieurs étapes aussi lentes les unes que les autres, et n’en corriger qu’une seule n’apporte aucun gain
Cela dit, c’est une interprétation bienveillante ; parfois, on se prend simplement au jeu de l’optimisation, on perd le sens des priorités, ou on fait une erreur
Même si les utilisateurs ne s’en rendent pas compte, réduire le temps de calcul d’un logiciel reste une bonne chose
Parce que cela réduit les coûts et facilite le passage à l’échelle
Si rendre le code plus rapide introduit une complexité excessive, alors même en laissant de côté la maintenabilité, cela finit par nuire aux performances à long terme à cause des conséquences en chaîne. Lors de changements d’architecture, du code qui deviendra inutile restera en place, et pour le comprendre ou le supprimer il faudra maîtriser toute la complexité du système
Le fait que « ce soit plus rapide » ne doit pas devenir une dispense morale permettant d’ignorer les inquiétudes liées à la complexité ou à la maintenabilité
Je suis actuellement dans une situation similaire, en train de faire passer via plusieurs petits projets des requêtes qui prenaient 5 minutes à moins de 30 secondes
Je dis bien à l’équipe que ce ne sera pas suffisant à long terme, mais c’est clairement une amélioration avec un impact important
Côté client, on passe d’une attente proprement exaspérante à quelque chose de simplement pénible
Pour l’instant, l’objectif n’est pas la performance par utilisateur, mais la performance globale. En optimisant des dizaines de processus de 5, 10 ou 30 minutes, on réduit fortement la contention avec d’autres parties du système. Marteler la base de données pendant 10 minutes, c’est extrêmement long ; au final, tout devient plus rapide et tout le monde y gagne