Gérer la résilience de vos données

Julien Hatzig
Just-Tech-IT
Published in
7 min readMay 27, 2020

Dans mon précédent article, je vous ai présenté le blue/green dans l’écosystème Azure. Dans cet article, nous allons répondre à la problématique suivante :

Comment minimiser les impacts sur votre code et votre base de données lors du déploiement d’une nouvelle version de votre application, en anticipant le retour arrière tout en garantissant un haut niveau de disponibilité pour vos utilisateurs ?

Dans le cas d’un déploiement, vous pouvez faire appel à un groupe d’utilisateurs et/ou tester en interne pendant plusieurs heures la nouvelle version avant de la diffuser plus largement. La version à venir et la version actuellement en production peuvent donc cohabiter plusieurs minutes, heures, jours en fonction de vos règles de déploiement. C’est le principe du pattern Blue/Green Deployment.

Place à un peu de théorie. Pour garantir la disponibilité de votre application vous allez devoir fonctionner en plusieurs phases :

  1. Une phase “initiale” : l’état d’origine de votre application.
  2. Une phase “intermédiaire” : l’état dans lequel deux versions de votre application cohabitent sur la même base de données. Cette phase peut être itérative.
  3. Une phase “finale” : l’état définitif de votre application (code et base de données).

Pour passer d’un état à l’autre, il faudra également prévoir des scripts SQL :

  1. Un script d’initialisation : ce script ajoutera votre nouveau champ mais permettra également l’alimentation en données de ce champ.
  2. Un script de transition : ce script a pour but de gérer un schéma transitoire de votre base de données, cela permettra à votre version “Blue” et “Green” de fonctionner en parallèle.
  3. Un script de validation : qui permettra d’arriver au schéma définitif mais aussi de “faire le ménage” dans les données et champs devenus obsolètes.
  4. Un script de rollback : qui en cas de retour arrière (un bug par exemple) vous permettra de revenir à l’état initial.
Fini la théorie. Place à la pratique.
  • Cas n°1 : Vous rajoutez un nouveau champ dans une table de votre base.

Prenons un exemple simple, vous possédez une table Assuré, pour répondre à un nouveau besoin un champ Adresse doit être ajouté.

Lors du déploiement de votre nouvelle version, vous devez vous assurer que votre nouveau schéma SQL reste compatible avec votre version blue. C’est la phase intermédiaire.

Vous allez donc devoir modifier le schéma de votre base pour y intégrer ce nouveau champ, mais attention, si ce champ est déclaré comme étant obligatoire, votre application actuellement en production ne fonctionnera plus. En effet quand vous allez vouloir ajouter un nouveau client, le champ sera obligatoire mais votre interface ne permettra pas la saisie du champ adresse, un bug sera alors présent en production.

Votre champ «Adresse» doit absolument être non obligatoire et/ou posséder une valeur par défaut. Par exemple «à renseigner».

ALTER TABLE Assuré
ADD Adresse VARCHAR(255) NOT NULL
CONSTRAINT defaultValue DEFAULT ‘à renseigner’;

Avec votre métier, vous aurez sûrement à imaginer un scénario pour rattraper toutes les données avec la valeur “à renseigner”. Je vous propose deux scénarios possibles :
Scénario 1 : Dans la prochaine version de votre application, vous pouvez prévoir une option qui informe l’utilisateur qu’il doit compléter son profil.
Scénario 2 : Une fois la nouvelle version en production, vous pouvez également prévoir un script qui identifie les assurés avec un profil incomplet et vous pouvez choisir de les relancer (par email, par notifications).

Vos versions “Blue” & “Green” fonctionnant en parallèle, vous devrez gérer le rattrapage de ces données. En fonction de l’importance et de la criticité de celles-ci vous devrez définir le scénario le plus adapté.

  • Cas n°2 : Vous devez modifier un champ existant dans une table de votre base.

Travaillant de manière itérative, initialement, le champ Adresse était un simple champ texte, votre métier souhaite désormais pouvoir faire des filtres sur le code postal, la ville. Vous allez donc devoir faire émerger une nouvelle table et modifier le schéma de la table Assuré.

Le script de transition, vous permettra de migrer vos données vers la nouvelle table. Le script de validation vous permettra de nettoyer votre schéma afin de supprimer toutes traces du champ Adresse dans la table Assuré.

Ne prenez pas le réflexe de faire un ALTER TABLE, préférez toujours un CREATE TABLE

Toujours dans le but d’assurer une compatibilité entre vos versions “Blue” et “Green”, il n’est pas possible de simplement ajouter une table Adresse et d’associer une clé étrangère à la table Assuré, du moins, pas dans un premier temps. Vous allez devoir passer par une phase intermédiaire.

CREATE TABLE Adresse ( 
id INTEGER PRIMARY KEY AUTOINCREMENT,
assure_id INTEGER,
rue TEXT,
ville TEXT,
codePostal TEXT,
CONSTRAINT FK_AssureId FOREIGN KEY (Assure_id)
REFERENCES Assuré(id))

Votre table est désormais créée mais vide. Il va donc falloir l’alimenter avec toutes les données du champ Adresse présentes dans la table Assuré.
Par chance, vous utilisez une norme pour les adresses, et toutes les adresses ont la structure suivante :

Rue, Code Postal, Ville
20 avenue de Paris, 59000, Lille

Vous pouvez donc créer un script pour migrer les données du champ Adresse dans la table cible.

INSERT INTO Adresse (id_assure, rue, ville, codePostal)
SELECT
id,
STRING_SPLIT(adresse, ',')(0),
STRING_SPLIT(adresse, ',')(1),
STRING_SPLIT(adresse, ',')(2)
FROM Assure

Voila, vos données sont désormais présentes dans la table Adresse.

Pour assurer une compatibilité ascendante, ne supprimez pas le champ Adresse de la table Assuré, celui ci est toujours nécessaire pour votre version “Blue”. Cette requête SQL devra être jouée tant que la version “Blue” sera en production car votre version “Blue” alimentera toujours le champ Adresse de la table Assuré.

Il existe aussi la possibilité de mettre en place un TRIGGER qui alimentera automatiquement votre nouvelle table mais je ne le conseille pas. Les triggers sont à manipuler avec précaution, ils modifient automatiquement les données “dans le dos” et cela peut s’avérer dangereux.

Vous pouvez aussi décider que votre version “Green” continue temporairement d’alimenter le champ Adresse de la table Assuré en plus de table Adresse. Mais attention à bien désactiver cette fonctionnalité rapidement pour pouvoir passer vos scripts de validation et ainsi supprimer définitivement le champ Adresse de la table Assuré.

  • Cas n° 3 : Vous devez supprimer un champ dans une table de votre base

Votre métier ne souhaite pas garder l’âge de l’assuré, c’est une donnée qu’il n’est plus nécessaire de garder dans votre table Assuré. Vous êtes dans un cas similaire au cas n°2, si vous supprimez le champ de la base de données, le code de la version «Blue» ne fonctionnera plus.

Le script de validation peut être joué une fois votre bascule effectuée ou plus tard (c’est une action manuelle)

Dans le cas d’une suppression, il faut également préparer une phase de transition. Cette phase de transition va devoir se faire au niveau de votre code. Dans un premier temps, Il faut d’abord livrer une version du code qui n’accède plus à cette donnée. Une fois, ce code déployé en production, vous pourrez supprimer la donnée de votre base de données.

Évitez tant que possible de faire des SELECT * qui remontent l’intégralité des colonnes d’une table mais ne remontez que les colonnes nécessaires. En plus de gagner en temps de traitement, vous identifierez beaucoup plus facilement les impacts d’une suppression de champs.

  • Cas n°4: Vous devez revenir en arrière, Rollback !

Après plusieurs heures/jours en production, vous avez découvert un bug dans votre code, vous devez faire un retour arrière. Mais comment ? Votre schéma SQL ne correspond plus au schéma d’origine.

Dans une livraison, il faut être paré à toute éventualité. Dans la phase d’anticipation de votre livraison, vous avez préparé un fichier SQL de rollback, qui permettra de revenir au schéma d’origine mais également de sauvegarder le delta sur les données créées avec la version “Green” de votre application.

Vos scripts de rollback devront permettre de revenir a votre schéma d’origine mais aussi migrer les données du nouveau schéma vers l’ancien schéma.
// Création de la colonne 
IF NOT EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Assuré' AND COLUMN_NAME = 'adresse')
BEGIN
ALTER TABLE Assure
ADD adresse TEXT NULL
END;
// Insertion des données
INSERT INTO Assuré(adresse)
SELECT CONCAT(rue, ', ', codePostal, ', ', ville)
FROM Adresse
WHERE id_assure in ( SELECT id
FROM Assure
WHERE Adresse == 'à renseigner' OR == null)

Une fois vos scripts de rollback correctement exécutés, vous pouvez rebasculer vers le couloir “Blue”.

En conclusion, une base de données ne doit pas vous empêcher de livrer votre application à l’aide du pattern blue/green. Le mot clé est l’anticipation. Vous devez désormais préparer toutes évolutions de votre schéma SQL via des scripts qui assurent la compatibilité descendante, la migration de vos données mais aussi le retour arrière en cas de rollback.

Dès que vous le pouvez, entourez les fonctionnalités clés de votre application autour du pattern de feature flipping. En effet, pour gérer plus facilement les phases de transitions dans le code, vous pouvez mettre en place ce pattern de résilience autour des fonctionnalités clefs de votre application. Grâce à ce pattern vous pouvez désactiver la fonctionnalité accédant à la donnée pendant la phase de livraison.

Tout au long de l’article, j’ai pris l’exemple d’une base de données, mais le blue/green et la compatibilité ascendante s’applique également à la consommation d’une API / d’un micro service / d’un Web Service.

A vous de jouer !

NB: Dans cet article la version “Blue” correspond à votre production actuelle, la version “Green” à la prochaine version…

--

--