BLOG | 7 clés pour booster vos bases de données
19/12/2022
Need for Speed
1, 3, 5 ou 10 ?
Combien de secondes devez-vous attendre avant d’estimer qu’une application est lente ?
Crédits :Aleksandra Sapozhnikova
A l’heure du streaming, de l’information instantanée, la meilleure des applications sera rejetée si elle souffre de problèmes de performance. Et quand bien même vous pourriez revendiquer un certain éloge de la lenteur, il est probable que vos utilisateurs n’adhèrent pas à cette incursion philosophique.
Les GAFAM n’ont que faire du « lièvre et de la tortue », ils ont aboli le temps.
La vitesse l’a emporté, parfois sur l’intelligence, mais cela est un autre débat. Il faut donc aller vite.
? Mais, avant, faut qu'on revoit les bases ?
Et parce que les bases de données sont désormais ultrarapides, nous allons retourner la question : comment éviter de perdre du temps ?
? Simple, basique, okay ?
Warm-up
? Vous n'avez pas les bases, vous n'avez pas les bases ?
Notre expérience chez Klee Group, fondée sur le développement de nombreuses applications, nous montre que la plupart des problèmes de performance sont imputables à l’un des 7 principes que nous vous présentons ci-dessous.
Connaitre ces principes permet non seulement de concevoir des applications plus fluides, mais aussi, puisque l’erreur est humaine, de diagnostiquer et corriger les problèmes de performances quand malheureusement ils surviennent.
1 – Regrouper
Regroupez vos traitements et vos requêtes.
Crédits :Venti Views
Le regroupement des traitements et des requêtes constitue certainement le premier principe. Il est simple à énoncer. Il faut avouer qu’il est souvent assez simple à coder. Quant à son bénéfice, il est exceptionnel dès lors que la volumétrie augmente.
Mais alors pourquoi n’est-il pas toujours suivi ?
L’oubli de ce principe essentiel constitue, de notre expérience, la première cause de trop longues secondes d’attente pour les utilisateurs. Souvent, cela démarre par de bonnes intentions. L’accès unitaire à une entité est développé et fonctionne parfaitement. De nouveaux usages imposent d’accéder à une liste de ces entités.
(Par exemple liste des commandes en cours, liste des produits bio, liste des clients actifs…) Récupérant la liste des identifiants, puis réutilisant les accès unitaires, la liste des entités est ainsi créée par simple agrégation. En développement cela fonctionne parfaitement. La réutilisation est magnifique, elle minimise les tests. Certains voient même en cette approche une vertu du développement orienté objet. Hélas, en production, quand les volumétries prennent de l’épaisseur alors les temps de réponse explosent. En effet, la requête exécute n+1 appels là où un seul suffirait.
Remédiation
La remédiation est évidente, il suffit d’accéder en mode ensembliste aux entités.
Tips
Des outils comme les ORM amplifient ces mauvais usages, en activant par défaut des requêtes et traitements unitaires. Les ORM sont magiques, mais il est nécessaire de les maîtriser surtout lorsque les volumétries deviennent significatives. Sinon la magie devient illusion, et le temps se dilue.
Souvent simples à mettre en œuvre au démarrage, les gains sont impressionnants, surtout sur des fortes volumétries. Pour une application existante, la mise à jour est parfois plus délicate, en revanche les bénéfices sont toujours au rendez-vous.
2 – Colocaliser
Quand deux systèmes discutent beaucoup ensemble, rapprochez-les !
Crédits :Ralph (Ravi) Kayden
Si la première règle ressemble à du transport massifié, la seconde ressemble davantage à la promotion des circuits courts.
Une application informatique est un véritable système organique constitué de multiples sous-systèmes. Le passage d’un sous-système à un autre coûte des ressources et du temps, de la même façon que le franchissement d’une frontière.
L’appel à des web services se comptera en millisecondes lorsqu’ils sont locaux et en dixièmes voire centaines de millisecondes lorsqu’ils sont externes avec des gestions de clé d’api, des firewalls à traverser…
Inversement, les traitements opérés au sein d’un même espace de code se feront en nanosecondes quand seuls les accès mémoire sont utilisés. Soit un rapport de 1 à 10 millions.
La tendance actuelle consiste à distribuer les fonctions d’un système dans des microservices. Les gains en termes d’élasticité et de modularité sont au rendez-vous. Hélas ! Il faudra payer au prix fort les latences entre systèmes.
Remédiation
La remédiation consiste à mesurer puis diminuer au maximum les échanges intersystèmes et toujours privilégier les échanges intrasystème, circuit court !
De manière générale, il convient de trouver un juste équilibre entre la répartition de fonctions dans des composants, modules séparés pour casser la complexité d’un système et le fait de conserver côte à côte les traitements pour éviter de franchir les barrières des systèmes.
3 – Ne pas boucler
Pourquoi faire en plusieurs fois ce que l’on peut faire en une seule fois ?
Crédits :Ismail Merad
La plupart des traitements nécessitent d’itérer sur des données. Il est toutefois important de maîtriser l’itération structurante pour que l’on n’ait pas un emballement des performances. Si une itération, sur un ensemble de n éléments, exécute à chaque itération une requête, on obtient in fine n+1 requêtes. Mais si à chaque itération on a une nouvelle itération on peut aller à n^2 requêtes. Avec des tests à 100 entités, ça passe encore, mais en production les temps explosent avec une réponse quadratique par rapport au volume.
Je rappelle que la plupart des requêtes s’exécutent en n log(n). A comparer avec n^2.
Remédiation
Oui, il va falloir construire une requête, certes un peu plus compliquée, mais le jeu en vaut la chandelle.
Pour 100 000 éléments les performances seront 20 000 fois plus rapides. Et plus il y a de données, plus le gain est élevé !
Maîtriser les boucles, c’est maîtriser la complexité, ce qui n’empêche pas d’avoir du discernement.
Il faut estimer la complexité n / n log(n) / n^2 et la volumétrie en mode nominal.
Pour une petite itération, préférez la méthode la plus simple, la plus lisible.
Dès que l’itération dépasse 10^3, il convient de réfléchir.
Au-delà de 10^5, il ne faut plus réfléchir et détruire la boucle en intégrant les sous-requêtes directement dans la requête principale.
4 – Mesurer
« Ce qui ne se mesure pas ne s’améliore pas ».
William Edward Deming (célèbre inventeur de la roue qui porte son nom)
Crédits : Fleur
La citation du célèbre statisticien et qualiticien américain met en relief une évidence qui semble, hélas, parfois oubliée.
« C’est lent ».
Voilà, la phrase est lâchée. « Quelle page, quelle fonction, quelle requête ?
Est-ce arrivé une fois ou bien est-ce systématique ?
Lent combien ? 3s ou 30s. »
Et parfois on se retrouve démuni avec juste une fiche JIRA, où un utilisateur mécontent aura écrit sa colère « c’est trop lent ».
Si on avait écouté William, on aurait constaté les problèmes, on les aurait quantifiés et déjà effectué un premier diagnostic.
Remédiation
Mettre en œuvre une plateforme de mesure des performances. Ces outils s’appelaient auparavant APM, ils sont désormais inclus dans les plateformes d’observabilité.
Peu importe l’outil choisi, il en faut un.
Tips
Quitte à mettre en place une mesure des performances pour la base de données, utilisez un outil qui permette de traiter les performances des traitements, des webservices… bref un outil qui couvre le spectre de vos usages.
Sur une application complexe, l’observabilité est indispensable pour contrôler, alerter et diagnostiquer.
Monter une plateforme d’observabilité nécessite un peu de travail. Notons qu’il existe des solutions Saas qui se greffent facilement sur des systèmes existants. Il y a aussi des solutions On Premise qui s’installent facilement et permettent un bon monitoring.
Dans la plupart des cas, ces systèmes ne nécessitent pas de développement. Ils s’ajoutent à l’infrastructure.
5 – Reproduire
Un problème, que l’on ne peut pas reproduire, est-il vraiment un problème ?
Crédits :Pigsy Ginx
Quand un problème de performance survient en production, est-on en mesure de le reproduire ?
La question n’est pas aussi simple qu’il y parait, car il faut disposer d’une plateforme, sinon identique, du moins dimensionnée à une échelle raisonnable 1 ou ½ de la production.
Quand on parle de plateforme, on l’entend avec tous les gris-gris des protections réseau.
Et les données !
Il est nécessaire de disposer d’une masse représentative de données. Attention, il faut inclure le RGPD à l’équation, car il n’est pas toujours possible de récupérer les données de production. Parfois, il convient de les anonymiser. Parfois, il est même impossible de les récupérer, et en ce cas il faut un jeu de données témoin significatif.
Remédiation
Disposer d’une plateforme interne identique à la production (ou d’un ordre comparable) pour être en mesure de diagnostiquer des problèmes et de tester la plateforme dans des conditions similaires à la production.
Juste indispensable sur les systèmes complexes, disposer d’un environnement représentatif de la production nécessite des procédures de mises à jour automatisées, y compris pour charger les données.
6 – Modéliser
Au commencement il y a le modèle, et son créateur.
Crédits : Eliott Van Buggenhout
Avant même que les données n’eussent été présentes, il y eut le modèle et son créateur.
Les performances découlent souvent d’une modélisation bien pensée, qui exploite les caractéristiques de la base de données, à commencer par le moteur choisi (Relationnel, documentaire, graphe, série temporelle). Ensuite, il convient de s’intéresser à ses capacités propres (langage de requête, par exemple SQL et les aspects transactionnels ou non) et aussi aux modalités de déploiement (système centralisé, distribué, partitionné et autres sharding ou clustering).
La base relationnelle centralisée possède un spectre large, mais des alternatives sont parfois préférables. Ah le charme rafraîchissant des modèles en flocons au moment de Noël !
Dans le cas des systèmes complexes, le modèle est souvent, encore une fois, un arbitrage entre des dogmes (Tu ne dupliqueras pas, Tu ne dénormaliseras pas) et un certain pragmatisme.
Et oui, il faut, parfois, savoir s’affranchir de certaines règles pour garantir de bonnes performances.
Seuls les sages, expérimentés, sauront naviguer entre les écueils pour modéliser la perfection, fut elle atteignable.
7 – Cibler
Chercher une aiguille dans une botte de foin (ou pas)
Crédits : Annie Spratt
Pour des raisons de facilité, une pratique se répand qui consiste à rapatrier toutes les données d’une base puis d’effectuer en Java, .Net, PHP voire Python, des sélections.
Il faut bien comprendre que le requêtage natif en base, c’est-à-dire le SQL, est mal aimé et par conséquent mal maîtrisé par beaucoup de développeurs. Et puis il est tellement plus simple de récupérer une liste et ensuite d’utiliser les outils de filtre ultra puissants des langages évoqués au-dessus.
Puissants, oui, mais lents !
Remédiation
Il est toujours préférable de sélectionner, les données au cœur de la base, au risque de devoir récupérer une masse d’informations et de devoir itérer sur l’ensemble de ces données pour trouver celles qui conviennent.
Dès lors qu’il est possible de spécifier des conditions de ciblage dans une requête, il faut le faire. Vous vous assurerez de performances en croissance logarithmique quand l’approche non ciblée vous donnera une croissance au mieux linéaire.
Bonus – Optimisation
Les bases de données possèdent des ressources qu’il convient de suivre (CPU, RAM, I/O). L’utilisation d’indexes favorise les lectures avec un léger surcoût en écriture. L’ajout de mémoire, permet de décharger les disques et donc augmente les performances. Cependant l’ajout d’indexes ou de mémoire doit s’effectuer sur une base saine par ailleurs, car la mémoire n’est pas extensible à l’infini et le nombre d’indexes doit rester raisonnable.
Bonus – Cache
Les érudits demanderont, avec raison, pourquoi je n’ai pas évoqué le cache comme mesure fondamentale. Tout simplement parce qu’avant de mettre en œuvre un cache, il faut avoir respecté les principes précédents. Le cache permet d’éviter de traiter des demandes similaires. Malheureusement, le cache est trop souvent utilisé pour masquer des problèmes. Or ceux-ci réapparaissent dès qu’il faut rafraîchir le cache.
Le cache ne doit donc pas être un cache-misère, mais un véritable accélérateur de performances. Vous devez garder la maîtrise de vos requêtes, même lorsqu’elles sont cachées.
Pitstop
Crédits : Gustavo Campos
Cette déambulation dans les bases de données nous est venue, à mon équipe et à moi-même, car depuis quelque temps nous sommes souvent sollicités pour résoudre des problèmes de performances. Toujours les mêmes !
La perte d’intérêt pour le SQL, l’omniprésence des ORM, la puissance des langages back-end, les causes sont multiples.
Nous avons donc décidé de les répertorier et d’établir un catalogue de ces principes. Lorsqu’ils sont suivis avec discernement, ils permettent de disposer d’une base saine en matière de performances, et de les contrôler et analyser.
Sur des bases à forte volumétrie (au-delà de 100 000 éléments), l’application de ces principes vous aidera grandement à garantir de bonnes performances.
Sinon des pauses inopinées viendront ponctuer les belles journées surchargées de vos utilisateurs.
Pas certain qu’ils apprécient !
Retrouvez le chemin de la performance, boostez vos bases de données !
Philippe Chrétien, CTO Klee Group
PS : pour ceux qui n’ont pas les bases : https://youtu.be/2bjk26RwjyU