Optimiser son code pour plus de performance

culture générale informatique developpement Sep 19, 2022

Quand t'es développeur parfois on te demande de développer des "moulinettes"

 

Tu sais, les fameux scripts qui permettent de prendre des données d'un endroit, des les transformer et de les déposer ailleurs.

Ces fameuses moulinettes, il y en a des tonnes et elles sont partout.

Elles servent à faire communiquer des systèmes entre eux.

Sauf que parfois, ces moulinettes prennent des heures à s'exécuter la nuit

Tout le monde s'en fiche, car c'est la nuit. Du moment que c'est OK le matin pour le début de journée

Problème avec ça : le jour où ça plante dans la nuit, ben t'es embêté pour la faire tourner de nouveau en journée... ça prend une plombe. Les utilisateurs sont mécontents, car ils ne peuvent pas travailler.

Ton manager débarque "c'est quoi ce bordel"... (bon je m'emballe, mais t'as compris)

Le plus gros gain de performance que j'ai rencontré au fil des années concerne deux choses :

Les appels API et les insertions base de données

La version naïve des moulinettes

Prenons l'exemple courant suivant :

J'ai besoin d'une moulinette qui récupère via API un tableau de données d'un système.

Pour chaque ligne de ce tableau, je dois faire des transformations (le format de la date, la fusion de deux colonnes ...)

Quand c'est prêt, je dois injecter les données dans ma basse donnée dans le cloud.

L'algo que tout le monde fait :

  • Récupérer le nombre de lignes à traiter via API : nb

  • Faire une boucle for : pour i de 1 à nb

    • Récupérer par API, la donnée i

    • Faire les modifications sur la donnée i

    • Insérer la donnée i dans ma bdd

Simple, efficace, lisible et coder très rapidement.

On teste sur une dizaine de lignes. Ça tourne en 30 secondes.

Y'a pas de bug.

On passe en prod.

Le lendemain, pour 35.000 lignes, ça prend 5 heures au milieu de la nuit

La version "moins" naïve 

Tu te doutes bien qu'on peut faire un peu mieux (sinon mon article ne sert à rien)

Ce que le script ci-dessus ne dit pas

Un appel API est très couteux en temps :

  1. Il faut établir une connexion

  2. Il faut s'authentifier

  3. Demander l'information (dans notre cas, une ligne)

  4. Attendre que le serveur distant retourne l'info

  5. Fermer la connexion

C'est pareil pour une insertion BDD :

  1. Il faut établir une connexion

  2. Il faut s'authentifier

  3. Envoyer la requête INSERT INTO (dans notre cas, une ligne)

  4. Attendre que le serveur distant fasse les opérations

  5. Fermer la connexion

     

On se rend compte d'une chose

À chaque tour de boucle, on répète les 5 étapes ci-dessus deux fois (une fois pour l'API et une fois pour la BDD)

Si on le fait pour 10000 lignes, ça fait 100.000 étapes pour tout traiter

En réfléchissant, on voit qu'en fait, les étapes 1, 2, 3 et 5 pourraient être faites qu'une seule fois

Notre script deviendrait donc :

  • Ouvrir une connexion avec l'API

  • Ouvrir une connexion avec la BDD

  • Récupérer le nombre de lignes à traiter via API : nb

  • Faire une boucle for : pour i de 1 à nb

    • Récupérer par API, la donnée i

    • Faire les modifications sur la donnée i

    • Insérer la donnée i dans ma bdd

  • Fermer la connexion avec l'API

  • Fermer la connexion avec la BDD

On passerait de 100.000 étapes à ... 40.000 + 6 étapes

La version "encore moins" naïve

Petit problème avec le script juste au-dessus.

Autant on peut laisser la connexion ouverte avec une BDD, autant avec des API de type REST (Https...) ce n'est pas possible.

Et même, laisser une connexion ouverte avec une BDD c'est s'exposer à une coupure réseau en plein milieu et potentiellement un plantage du script (sans connaitre ce qu'il se passe vraiment)

Bon j'exagère volontairement le scénario pour bien mettre en évidence le sujet.

Pour optimiser encore plus le script, il est possible de faire des traitements "BULK" (en masse)

La plupart des API permettent de récupérer toutes les données en une seule fois

Et toutes les BDD permettent les INSERT d'un ensemble de données en une seule fois

Notre script deviendrait donc :

  • Récupérer toutes les données via API et stocker dans un tableau

  • Pour chaque ligne du tableau

    • Faire les modifications sur la ligne courante

  • Injecter le tableau modifié dans la BDD

J'ai vu un script qui prenait près de 10 heures de temps (35.000 lignes traitées à la vitesse d'une ligne par seconde) être optimisé pour ne prendre que 2 minutes : l'API donnait les 35.000 lignes d'un coup, mais était un peu lente, car distante. La modification du tableau était rapide. Et l'injection des 35.000 lignes dans Mysql prenait 2 secondes (dans le cloud).

Pour aller plus loin

  • Pense à logger le temps que prend tes scripts

    • Comme ça tu sais en cas de temps anormal (trop rapide ou trop lent) qu'il y a quelque chose qui cloche

  • Utilise de la supervision passive

    • C'est-à-dire qu'à la fin de ton script, il envoie une notification à un outil de supervision pour dire s'il a réussi ou pas

    • L'outil de supervision peut t'alerter en fonction des résultats et mieux il peut te dire "j'ai pas reçu de nouvelles de ton script depuis plus de 24h, va voir s'il est toujours OK"

  • Les optimisations, ça fait rêver, mais ça a un cout en développement. Il faut y passer du temps.

    • C'est pour ça, se concentrer sur les optimisations évidentes et rapides

    • Dès que tu en trouves une, tu la notes pour la retrouver facilement plus tard

    • Ensuite, regarder les optimisations qui ont vraiment un impact.

    • Si ton optimisation te fait passer de 5 minutes à 3 minutes pour un traitement de nuit, alors que ça te demande 2 h de dev, c'est pas rentable

    • À l'inverse, une optimisation qui fait passer une requête de 200ms à 50ms pour un site web avec des utilisateurs, là, ça vaut le coup

    • Tu as compris le truc

Conclusion 

Toujours commencer par la version Naïve et voir si ça suffit.

Ensuite, faire les 20% d'optimisation qui apporteront un gain de 80%.

Enfin, décider s'il faut aller plus loin en fonction du contexte.

Voilà :)

Imrane 🏖

La newsletter pour ne rien louper

Rejoins les 2500 lecteurs de  la newsletter pour obtenir des conseils, des stratégies et des ressources pour développer et monétiser tes compétences Tech.