feat: Updating realisation with more context and perf analysis
This commit is contained in:
parent
873b1acc1d
commit
d97b76baef
@ -47,7 +47,7 @@ Un projet C\# dans l'environnement Microsoft est composé d'une solution, de sou
|
|||||||
Les sous-solutions d'un projet sont des solutions indépendantes intégrées au projet. Un peu à la manière de librairies, je peux créer du code qui pourra être réutilisé dans différents projets indépendamment, sans devoir le dupliquer.\
|
Les sous-solutions d'un projet sont des solutions indépendantes intégrées au projet. Un peu à la manière de librairies, je peux créer du code qui pourra être réutilisé dans différents projets indépendamment, sans devoir le dupliquer.\
|
||||||
Chaque projet possède ses propres NuGet packages, mais la solution peut gérer des dépendances, c'est-à-dire que le package sera ajouté à la liste des dépendances globales et sera installé dans tous les projets de la solution.
|
Chaque projet possède ses propres NuGet packages, mais la solution peut gérer des dépendances, c'est-à-dire que le package sera ajouté à la liste des dépendances globales et sera installé dans tous les projets de la solution.
|
||||||
|
|
||||||
Dans mon cas, la solution #ref-glossary(term: "Back-End")[back-end] d'InfSuite est composé de 65 projets. Il y a le projet "WebApi" qui gère les routes et les interactions avec l'application #ref-glossary(term: "Front-End")[front-end] qui est disponible pour le client et qui dépend du projet "Server". Le projet "Server", lui, contient la logique de certaines interactions simples, par exemple la recherche d'IO via la barre de recherche dans l'application. Le projet "Server" dépend lui du projet "Core" qui gère certaines fonctionnalités plus poussées de l'application autant pour la partie web que pour d'autres composants. Il existe de nombreuses autres dépendances dans l'application qui complexifient la gestion des packages. Par exemple dans le diagramme @ik-webapi-dependencies, on remarque rapidement que les dépendances internes au projet sont déjà relativement complexes.
|
Dans mon cas, la solution #ref-glossary(term: "Back-End")[back-end] d'InfSuite est composé de 65 projets. Il y a le projet "WebApi" qui gère les routes et les interactions avec l'application #ref-glossary(term: "Front-End")[front-end] qui est disponible pour le client et qui dépend du projet "Server". Le projet "Server", lui, contient la logique de certaines interactions simples, par exemple la recherche d'IO via la barre de recherche dans l'application. Le projet "Server" dépend du projet "Core" qui gère certaines fonctionnalités plus poussées de l'application autant pour la partie web que pour d'autres composants. Il existe de nombreuses autres dépendances dans l'application qui complexifient la gestion des packages. Par exemple dans le diagramme @ik-webapi-dependencies, on remarque rapidement que les dépendances internes au projet peuvent être relativement complexes.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
image("../assets/images/ik-webapi-dependencies.png"),
|
image("../assets/images/ik-webapi-dependencies.png"),
|
||||||
@ -56,14 +56,41 @@ Dans mon cas, la solution #ref-glossary(term: "Back-End")[back-end] d'InfSuite e
|
|||||||
|
|
||||||
Si je souhaite par exemple mettre à jour un package dans le projet "Geometry", tous les projets dépendants sont impactés par cette mise à jour, il faut donc s'assurer que rien ne vient casser le bon fonctionnement de l'application en profondeur. Je m'intéresse donc aux liens entre les différents projets ainsi qu'aux librairies que je souhaite mettre à jour pour m'assurer de leur compatibilité pour toute l'application.
|
Si je souhaite par exemple mettre à jour un package dans le projet "Geometry", tous les projets dépendants sont impactés par cette mise à jour, il faut donc s'assurer que rien ne vient casser le bon fonctionnement de l'application en profondeur. Je m'intéresse donc aux liens entre les différents projets ainsi qu'aux librairies que je souhaite mettre à jour pour m'assurer de leur compatibilité pour toute l'application.
|
||||||
|
|
||||||
=== Compatibilité
|
=== Compatibilité et décision
|
||||||
|
|
||||||
|
La première étape est de valider la compatibilité entre la version 14 et 16 de PostgreSQL. Une première manière de valider cela est d'aller sur les notes de mise à jour sur le site officiel et de chercher les changements qui peuvent affecter la compatibilité entre les deux bases.\
|
||||||
|
Après avoir analysé en détail les changements il y a trois grandes catégories. Il y a l'impact sur l'administration système, celui sur les requêtes SQL et celui sur l'incompatibilité des données. La partie administration système n'est pas gérée par les développeurs d'InfSuite, elle est gérée par d'autres employés de l'entreprise, je peux donc me concentrer sur la partie requêtes et données.\
|
||||||
|
Pour la partie des données stockées en analysant les données actuelles je peux relever quelques changements qu'il faut surveiller:
|
||||||
|
- Les jsonb peuvent être utilisé par les systèmes d'informations géographiques pour stocker les informations géographiques et attributaires. Il faut donc surveiller le comportement de l'application à ce niveau.
|
||||||
|
- Les uuid qui ont subits des optimisations pour mieux gérer les identifiants uniques universels et qui est utilisé comme identifiants uniques pour les tables dans le projet.
|
||||||
|
- Les types numeric qui sont également utilisés dans l'application qui subisse des optimisations de performances.
|
||||||
|
Il n'existe pas d'autre changement majeur qui pourrait porter atteinte à l'intégrité des données lors de la migration.
|
||||||
|
|
||||||
|
Une fois la première étape validée pour l'intégrité théorique des données, il faut valider la seconde étape qui est la réalisation de la migration. Le seul moyen de s'assurer de la complète compatibilité entre les deux systèmes est d'effectuer une première migration dite "à blanc". Elle a pour but de mettre en place un système séparé de l'environnement de production, pour s'assurer de ne pas impacter l'application accessible par les clients.\
|
||||||
|
L'objectif de ce système est d'avoir une base de tests sur laquelle je peux m'assurer que l'application fonctionne toujours après la migration de données et que si des problèmes s'annoncent, il n'y ait aucun autre impact que de les constater.
|
||||||
|
|
||||||
|
Avec la validation obtenue précédemment, sur la compatibilité des deux systèmes, j'ai pu valider, sous l'approbation de mon chef de projet et de l'architecte d'application, que la migration la plus adaptée dans notre cas, serait une migration hybride.\
|
||||||
|
Le but de la migration hybride est de combiner deux types de migration de données que j'ai pu citer précédemment dans ce document. Comme je veux ajouter un fuseau horaire aux horodatages qui servent de versions, je dois modifier les données de la base source. Cependant, cela implique de modifier les données et les modèle de données associés.\
|
||||||
|
Pour éviter de devoir utiliser un logiciel tel que PgAdmin et de passer du temps à manipuler le modèle de données qui pourrait causer des problèmes, je préfère utiliser des outils bien maîtrisés et intégrés sur le projet InfSuite.
|
||||||
|
|
||||||
|
Pour l'import de données, cette tâche a été réalisée par un administrateur système de l'entreprise. Il a utilisé la méthode d'import d'un fichier #ref-glossary(term: "Dump")[dump] de la base source dans la nouvelle base. Je l'ai présenté ci-dessus, n'ayant aucun soucis de compatibilité sur les types de données, l'intégration de ces données s'est faite sans accros dans la base de test.
|
||||||
|
|
||||||
|
Pour mettre à jour le modèle de données de manière synchrone avec les mises à jour de l'application et éviter des soucis de compatibilités, l'environnement InfSuite utilise un système de fichiers scripts. Rédigés en SQL, ces scripts viennent mettre à jour le schéma de base de données et sont exécutés automatiquement par le serveur lors de la mise à jour de l'environnement ciblé (dev, staging, production, etc.).
|
||||||
|
|
||||||
|
Pour l'exemple des horodatages, je rédige un script SQL que je pourrais exécuter manuellement sur l'environnement de développement avec la nouvelle version de PostgreSQL et effectuer mes tests. Cependant, si je veux intégrer mes modifications sur les autres environnements, il faut que je sauvegarde mes changements sur Azure Devops, je n'ai pas la permission de faire ces changements manuellement.
|
||||||
|
|
||||||
|
Enfin, pour mettre à jour les données dans la base une fois le schéma de base modifié, je décide de faire cette migration en temps réel. La compatibilité entre les types de données ``` timestamp``` et ```timestamptz``` permet de garder en base l'ancien format de version, de mettre à jour le schéma de base puis de mettre à jour les données en y rajoutant le fuseau horaire. Comme la colonne "version" est utilisée à de nombreux endroits, créer un type de donnée côté serveur qui va s'occuper de les traiter rend la tâche moins complexe et chronophage. Avant de passer sur la réalisation, je dois m'assurer de la compatibilité des dépendances externes pour effectuer la migration.
|
||||||
|
|
||||||
|
Ce qui m'intéresse particulièrement ici, est de mettre à jour le package Npgsql car il permet de communiquer avec la base de données. Dans une application .NET, il y a la possibilité d'utiliser un #ref-glossary(term: "ORM")[#display-def("ORM")] pour simplifier les interactions avec les bases de données. Le projet InfSuite utilise historiquement l'#ref-glossary(term: "ORM")[ORM] #ref-glossary(term: "EF")[EntityFramework]. Il faut bien différencier #ref-glossary(term: "EF")[EntityFramework] qui n'est plus activement développé, de son successeur EntityFrameworkCore qui offre de nouvelles fonctionnalités qui ne seront plus implémentées dans #ref-glossary(term: "EF")[EntityFramework].
|
||||||
|
|
||||||
|
#ref-glossary(term: "EF")[EntityFramework] utilise le connecteur Npgsql pour effectuer les requêtes vers la base de données. En recherchant les versions disponibles de Npgsql disponibles pour EntityFramework, je me suis rendu compte qu'il fallait prêter attention à une fonctionnalité importante de PostgreSQL que le projet InfSuite veut maintenant exploiter : les horodatages avec des fuseaux horaires.\
|
||||||
|
La version post mise à jour de Npgsql était la version ``` 4.1.13``` et la dernière version disponible qui utilise les horodatages avec fuseau horaire est la version ``` 8.0.3```. En essayant de le mettre à jour avec cette version, je me suis rendu compte qu'#ref-glossary(term: "EF")[EF] n'était pas compatible avec la version ``` 8.0.3```. La dernière version du paquet Npgsql disponible pour #ref-glossary(term: "EF")[EF] étant la version ``` 6.4.3``` je dois donc me contenter de cette version.
|
||||||
|
|
||||||
Ce qui m'intéresse particulièrement ici, est de mettre à jour le package Npgsql car il permet de communiquer avec la base de données. Dans une application .NET, il y a la possibilité d'utiliser un #ref-glossary(term: "ORM")[#display-def("ORM")] pour simplifier les interactions avec les bases de données. Le projet InfSuite utilise historiquement l'#ref-glossary(term: "ORM")[ORM] #ref-glossary(term: "EF")[EntityFramework]. Il faut bien différencier #ref-glossary(term: "EF")[EntityFramework] qui n'est plus activement développé, de son successeur EntityFrameworkCore qui offre de nouvelles fonctionnalités qui ne seront plus implémentées dans #ref-glossary(term: "EF")[EntityFramework].\
|
|
||||||
#ref-glossary(term: "EF")[EntityFramework] utilise le connecteur Npgsql pour effectuer les requêtes vers la base de données. En recherchant les versions disponibles de Npgsql disponibles pour EntityFramework, je me suis rendu compte qu'il fallait prêter attention à une fonctionnalité importante de PostgreSQL que le projet InfSuite veut maintenant exploiter : les horodatages avec des fuseaux horaires.
|
|
||||||
La version post mise à jour de Npgsql était la version ``` 4.1.13``` et la dernière version disponible qui utilise les horodatages avec fuseau horaire est la version ``` 8.0.3```. En essayant de le mettre à jour avec cette version, je me suis rendu compte qu'#ref-glossary(term: "EF")[EF] n'était pas compatible avec la version ``` 8.0.3```. La dernière version du paquet Npgsql disponible pour #ref-glossary(term: "EF")[EF] étant la version ``` 6.4.3``` je dois donc me contenter de cette version.\
|
|
||||||
Avant de valider l'utilisation de ce dernier dans toute l'application, je dois valider qu'elle supporte les horodatages avec fuseau horaire et qu'elle est également compatible avec le reste de l'application. En se référant à la documentation fournie, la première version à intégrer les horodatages avec fuseau horaire est bien la version ``` 6.X.X``` d'Npgsql, elle est donc compatible avec le besoin de sauvegarder les fuseaux horaires pour les versions.
|
Avant de valider l'utilisation de ce dernier dans toute l'application, je dois valider qu'elle supporte les horodatages avec fuseau horaire et qu'elle est également compatible avec le reste de l'application. En se référant à la documentation fournie, la première version à intégrer les horodatages avec fuseau horaire est bien la version ``` 6.X.X``` d'Npgsql, elle est donc compatible avec le besoin de sauvegarder les fuseaux horaires pour les versions.
|
||||||
|
|
||||||
Si on souhaite passer sur la nouvelle version du paquet Npgsql, la version ``` 8.X.X```, il n'y a pas d'autre choix que de passer d'EF à EFCore. Faire le choix de mettre à jour l'application EFCore permettrait de compléter l'objectif de maintenir l'application à jour et saine. En effet, pour rappel, EF n'est maintenant plus mis à jour régulièrement. L'étude d'impact des couts et des changements impliqués par une telle mise à jour a déjà été réalisé à priori de mon analyse et il en est ressorti que pour l'année courrante, un tel budget ne pouvait pas être accordé pour cette mise à jour. Si je veux mettre à jour l'application pour utiliser les dernières fonctionnalités disponibles sans passer par une mise à jour d'EF, le seul choix qu'il reste est de mettre à jour Npgsql vers la version ``` 6.X.X```. Le schéma @npgsql-versions-incompatibilty ci-dessous résume la situation d'incompatibilités entre les versions des trois éléments à savoir respectivement : à gauche Entity Framework, au centre le paquet Npgsql et à droite la base de données PostgreSQL.
|
Si on souhaite passer sur la nouvelle version du paquet Npgsql, la version ``` 8.X.X```, il n'y a pas d'autre choix que de passer d'EF à EFCore. Faire le choix de mettre à jour l'application EFCore permettrait de compléter l'objectif de maintenir l'application à jour et saine. En effet, pour rappel, EF n'est maintenant plus mis à jour régulièrement.\
|
||||||
|
L'étude d'impact des couts et des changements impliqués par une telle mise à jour a déjà été réalisé à priori de mon analyse et il en est ressorti que pour l'année courrante, un tel budget ne pouvait pas être accordé pour cette mise à jour. Si je veux mettre à jour l'application pour utiliser les dernières fonctionnalités disponibles sans passer par une mise à jour d'EF, le seul choix qu'il reste est de mettre à jour Npgsql vers la version ``` 6.X.X```.\
|
||||||
|
Le schéma @npgsql-versions-incompatibilty ci-dessous résume la situation d'incompatibilités entre les versions des trois éléments à savoir respectivement : à gauche Entity Framework, au centre le paquet Npgsql et à droite la base de données PostgreSQL.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
image("../assets/images/npgsql-versions-incompatibilty.png"),
|
image("../assets/images/npgsql-versions-incompatibilty.png"),
|
||||||
@ -78,11 +105,34 @@ Pour effectuer un test de performance, le système utilise une fonctionnalité g
|
|||||||
|
|
||||||
Le premier type de filtres est un filtre statique. Peu gourmand en ressource et très simple d'utilisation, on peut y ajouter des entités manuellement et cela va permettre de n'afficher que les objets sélectionnés dans l'application. Fonctionnellement parlant ce n'est qu'une relation de base de données.
|
Le premier type de filtres est un filtre statique. Peu gourmand en ressource et très simple d'utilisation, on peut y ajouter des entités manuellement et cela va permettre de n'afficher que les objets sélectionnés dans l'application. Fonctionnellement parlant ce n'est qu'une relation de base de données.
|
||||||
|
|
||||||
Le second type de filtre, plus complexe, est le filtre dynamique. Les filtres dynamiques permettent de gérer automatiquement les entités qui seront incluses ou exclues de l'affichage. Pour ce type de filtre, il est possible créer des règles de filtrage avancées pour permettre à l'utilisateur plus de flexibilité.\ Un peu à la manière d'une requête SQL, peut construire une requête qui va être exécutée pour permettre de retrouver les entités à partir de ces critères. Il peut par exemple demander de filtre les ouvrages par position géographique en ne prenant en compte que ceux au-dessus d'une certaine latitude et uniquement les ouvrages qui contiennent un certain numéro dans leur nom.\
|
Le second type de filtre, plus complexe, est le filtre dynamique. Les filtres dynamiques permettent de gérer automatiquement les entités qui seront incluses ou exclues de l'affichage. Pour ce type de filtre, il est possible de créer des règles de filtrage avancées pour permettre à l'utilisateur plus de flexibilité.\
|
||||||
Il est possible de créer des règles avec chaque propriété d'un objet d'infrastructure, d'appliquer un ordre pour les conditions, de faire des agrégats…. Les utilisateurs ont la liberté de créer leur propre requête, une requête pouvant devenir rapidement complexe, elle peut prendre plus de temps à filtrer les objets d'infrastructures pour les retourner à l'utilisateur.
|
Un peu à la manière d'une requête SQL, il est possible de construire une requête qui va être exécutée pour permettre de retrouver les entités à partir de critères. Il est par exemple possible de demander de filtrer les ouvrages par position géographique en ne prenant en compte que ceux au-dessus d'une certaine latitude et de rajouter à ce filtre uniquement les ouvrages qui contiennent un certain numéro dans leur nom.\
|
||||||
|
Il est possible de créer des règles avec chaque propriété d'un objet d'infrastructure, d'appliquer un ordre pour les conditions, de faire des agrégats, des jointures,... Les utilisateurs ont la liberté de créer leur propre requête, une requête pouvant devenir rapidement complexe, elle peut donc prendre plus de temps à filtrer les objets d'infrastructures pour les retourner à l'utilisateur.\
|
||||||
|
Étant utilisé par les services GIS de l'application, s'assurer de la performance de ce système est primordial.
|
||||||
|
|
||||||
Ce que l'outil permet de tester est ce système de groupe/filtres. Il va chercher les différents filtres existants en base de données, peu importe le client qui a pu les créer, et les exécuter.\
|
Ce que l'outil permet de tester est ce système de groupe/filtres. Il va chercher les différents filtres existants en base de données, peu importe le client qui a pu les créer, et les exécuter.\
|
||||||
Cette méthode permet de connaître les performances réelles de la base dans un cas pratique et non pas d'avoir des performances théoriques fournies par les développeurs du #ref-glossary(term: "SGBDR")[SGBDR] qui peuvent être tournées en leur faveur. Nous cherchons donc à savoir si le chiffre de 10% de performances en plus donné par les développeurs est véridique.
|
Cette méthode permet de connaître les performances réelles de la base dans un cas pratique spécifique à l'application et non pas d'avoir des performances théoriques fournies par les développeurs du #ref-glossary(term: "SGBDR")[SGBDR] qui peuvent être tournées en leur faveur. Nous cherchons donc à savoir si le chiffre de 10% en gain de performances est réel ou non.
|
||||||
|
|
||||||
|
L'objectif est donc de comparer les performances de la base de production encore sous PostgreSQL 14, avec les performances d'une base de développement installée pour l'occasion, elle, sous PostgreSQL 16. Après avoir exécuté l'outil de benchmark sur les deux bases, je récupère les données brutes en sortie de programme pour les analyser. Ci-dessous un exemple de données de sorties fournies par le programme après execution.
|
||||||
|
|
||||||
|
```csv
|
||||||
|
eruid,description
|
||||||
|
batman,uses technology
|
||||||
|
superman,flies through the air
|
||||||
|
spiderman,uses a web
|
||||||
|
ghostrider, rides a motorcycle
|
||||||
|
#GROUP_OBJECT_PROFILE#accessgroupGroupProfile
|
||||||
|
cn,description
|
||||||
|
daredevil,this group represents daredevils
|
||||||
|
superhero,this group represents superheroes
|
||||||
|
#GROUP_OBJECT_PROFILE#aixaccessgroupGroupProfile
|
||||||
|
aixgroupadminlist,ibm-aixprojectnamelist
|
||||||
|
eadmins,eadmingroup
|
||||||
|
eguests,eguestgroup
|
||||||
|
```
|
||||||
|
|
||||||
|
Les données sont au format CSV, je peux ainsi les importer dans un logiciel tableur tel qu'Excel pour les manipuler et les comparer. L'application de production étant accessibles aux clients en continu, les données stockées peuvent changer très rapidement et présenter un delta avec les données sauvegardées à posteriori lors la mise en place de la base de développement.\
|
||||||
|
Cette différence doit être prise en compte dans la comparaison des données puisque je dois alors utiliser des fonctions plus poussées d'Excel pour retrouver les données similaires entre les deux tables et en exploiter les résultats.
|
||||||
|
|
||||||
#pagebreak(weak: true)
|
#pagebreak(weak: true)
|
||||||
== Adaptation du code
|
== Adaptation du code
|
||||||
|
Loading…
Reference in New Issue
Block a user