Il y a environ deux ans, j’ai travaillé sur un projet où nous devions migrer une application d’entreprise d’un MPP vers Spark avec Delta.io sur un environnement Hadoop sur site.
Nous avions environ 17 000 instructions SQL dans 4 000 fichiers. Ces 4 000 fichiers ont ensuite été exécutés selon un calendrier. Pour l’exécution, les SQL ont été exécutés sur le MPP à l’aide d’un pilote de base de données personnalisé. Ouais. En effet, l’application s’est développée sur une période de 20 ans.
Lorsque nous avons commencé, nous avions toutes les instructions SQL, qui devaient être converties pour être compatibles avec la syntaxe Spark SQL. De plus, le planificateur devait être remplacé par Airflow. Donc, comme toujours, le délai était assez agressif. Mais ce n’est pas l’histoire.
Pour exécuter les SQL sur la plate-forme cible, nous avons dû créer un framework Python. Ensuite, en utilisant des métadonnées appropriées, nous avons généré les applications PySpark. Le générateur a renvoyé les SQL à partir d’Excel, puis les a stockés dans la structure requise. Chaque programme était indépendant et avait une ou plusieurs instructions SQL exécutées à l’aide de SparkSQL. Avant d’exécuter les programmes selon un calendrier, nous devions nous assurer que chaque application fonctionnait comme prévu. Pour cela, l’équipe a soumis chaque candidature et vérifié ses résultats. Les requêtes SQL et le framework Python ont été modifiés au besoin en parallèle. Chaque application PySpark était indépendante. En d’autres termes, tout ce dont il avait besoin pour l’exécution était disponible dans le même programme. Un inconvénient était que chaque application se terminait par la répétition des mêmes méthodes. Quelles méthodes ? Nous avions une méthode pour exécuter un SQL tel qu’il s’occupait des exceptions et ne renvoyait qu’un vrai/faux, selon l’exécution. Nous avions également une méthode pour récupérer les valeurs des paramètres et les remplir dans l’instruction SQL avant de l’exécuter. Ainsi, ces deux méthodes ont été répétées dans chaque programme.
Vous pouvez demander pourquoi ne pas stocker les SQL dans une base de données et demander au framework d’extraire les requêtes de la base de données. Quatre raisons, la première étant le temps. Chaque connexion à la base de données prend du temps supplémentaire. La deuxième raison était liée à la modification SQL. Comme les SQL du fichier Python et de chaque fichier étaient indépendants, chaque développeur pouvait modifier son fichier, apporter des modifications et soumettre l’application sans affecter aucun autre script. Enfin, nous avons eu des cas où des personnes ont écrasé leurs propres fichiers.
Dans certains cas, nous avons également perdu quelques fichiers. La troisième raison était la capacité d’une cellule de base de données à être un véritable éditeur. L’équipe devrait donc copier et coller le code dans un éditeur comme Notepad ++ (je sais. Les gens ne sont pas à l’aise avec vi), modifier le programme, puis remettre la requête dans la cellule appropriée. Et ici, le « propre » est important. Compte tenu des éditeurs de base de données typiques que nous utilisons, il est assez facile d’écraser une autre cellule. Le quatrième point est le nombre de personnes qui modifient la base de données simultanément. Imaginez 40 personnes éditant le même tableau. Ce serait une histoire d’horreur classique.
Lorsque nous avons commencé à exécuter les applications PySpark via Airflow, nous avons constaté que l’initialisation de la session Spark prenait beaucoup de temps. Si nous pouvions combiner l’exécution de plusieurs applications PySpark, nous pourrions gagner du temps. Cela ne semble-t-il pas une idée merveilleuse? ‘Combinez plusieurs applications PySpark en une seule application.’ La question était, comment allions-nous le faire avec un impact minimal sur le délai de livraison ? Même si nous prenions le temps de former et de guider chaque membre de l’équipe sur les changements nécessaires, nous recherchions l’effort important. Combiner plusieurs applications PySpark n’était pas anodin. Premièrement, nous devions éditer chaque fichier, supprimer les méthodes courantes et déplacer le code présent dans le ‘main’ dans une méthode avec les paramètres requis. Ensuite, nous devions écrire un autre programme qui devait importer les scripts modifiés et les exécuter dans le bon ordre.
C’était une tâche assez monumentale, compte tenu du nombre de membres de l’équipe et du nombre de dossiers impliqués.
J’ai fait la meilleure chose suivante; J’ai automatisé le processus.
J’ai écrit un programme Python pour parcourir chaque script, extraire les instructions SQL de chaque script et les télécharger dans le bon ordre dans une base de données SQLite. Pourquoi pas Excel ? Parce que certains SQL étaient si volumineux qu’ils dépassaient la limite de caractères d’une cellule dans Excel. J’ai donc dû utiliser une base de données. Exécuter un serveur distant aurait pris du temps. Une base de données locale comme SQLite était donc la meilleure option. Étant donné que les applications PySpark étaient générées par un programme, la structure et la dénomination des méthodes et des variables étaient bien définies et il n’y avait aucun changement. Une base de données distante a également ajouté au temps nécessaire à la génération d’applications. Avec Excel ou SQLite, le temps de génération du code était d’environ 15 minutes. Avec une base de données distante, l’application avait besoin de deux heures pour générer le code.
Après avoir extrait tous les SQL dans une table de base de données, j’ai eu la liberté de reconcevoir l’architecture et d’utiliser des classes et des méthodes communes. La nouvelle version du générateur d’application a créé le script sans ‘main’ et a également généré un programme qui a exécuté les scripts sans main dans l’ordre requis. Tous les noms de scripts et leur ordre ont été gérés à l’aide de métadonnées appropriées.
J’ai réussi à extraire les SQL de 95 % des applications PySpark – et le temps d’exécution était de quelques minutes. La tâche n’a pris qu’environ 10 à 15 minutes pour traiter environ 4000 scripts. J’ai fini par épargner à l’équipe de nombreux jours de travail banal. À toutes fins pratiques, l’équipe a continué à utiliser les scripts shell d’assistance pour l’exécution de l’application, bien que les scripts d’assistance aient également dû être modifiés.
Combien de temps avons-nous gagné en changeant l’architecture ? Nous avons coupé environ quatre heures du programme, qui fonctionnait auparavant pendant environ 24 heures. Évidemment, beaucoup plus d’optimisation devait suivre car le planning était censé s’exécuter en huit heures et donc s’exécuter trois fois par jour.
Qu’avons-nous appris de cet exercice ?
- Nous devons trouver du temps pour la conception. Si nous prenons de mauvaises décisions de conception, nous sommes confrontés à des conséquences à long terme.
- Faites une vraie réflexion hors de la boîte et essayez une approche scandaleuse. Vous pourriez vous surprendre.
- Croyez en vous et en votre équipe.