Nos instances Cloud SQL constituent un élément central de l'architecture de construction de l'index de Glean. Elles servent notamment de référentiel pour toutes nos données explorées, qui finissent par rejoindre l'index servi. Elles stockent également d'autres informations, comme les réponses créées par les utilisateurs de Glean. À nos débuts chez Glean, nous enregistrions tout cela dans Google Big Table, mais nous l'avons ensuite déplacé vers Cloud SQL pour des raisons de coût. Historiquement, toutes nos instances Cloud SQL étaient des instances MySQL5. Nous avons récemment décidé de migrer ces instances vers MySQL8, après que GCP a commencé à prendre en charge MySQL8.
Motivation
Outre l'utilisation de la toute dernière version, la principale motivation derrière cette migration résidait dans les améliorations JSON introduites avec MySQL8. Avant MySQL8, nous avons rencontré des cas où certaines mises à niveau prenaient près de 48 heures, car certaines commandes Alter Table opérant sur les colonnes JSON mettaient beaucoup de temps à s'exécuter. Nous pensions que l'utilisation de MySQL8 nous permettrait d'accélérer considérablement ce type d'opérations, car nous pourrions être en mesure de mettre à jour le JSON directement en place.
Principaux défis
- Comme il s'agissait d'une mise à niveau de version majeure, nous devions créer une toute nouvelle instance MySQL8, puis y copier les données de l'ancienne instance. Le volume de données à copier était assez important dans certains de nos déploiements, atteignant plusieurs To.
- Pendant la copie des données, la base de données source devait rester disponible pour un fonctionnement normal.
- Selon la manière dont nos services se connectaient à la base de données, une fois le basculement de l'ancienne base vers la nouvelle effectué, certains services devraient être redémarrés, tandis que d'autres devraient être redéployés. Nous avons également mis en place certains services capables de détecter la modification des paramètres de connexion GCP et d'actualiser ainsi leurs pools de connexions SQL en mémoire, éliminant de ce fait le besoin de redémarrage ou de redéploiement.
- Comme le basculement pouvait impliquer le redéploiement de certains services, celui-ci devait se faire sous la supervision de quelqu'un. Cela signifiait également qu'il ne pouvait avoir lieu que lorsque la charge client sur le système était faible.
Utilisation de GCP DMS
Compte tenu des contraintes ci-dessus, nous avons décidé d'utiliser GCP DMS pour migrer nos bases de données de MySQL5 vers MySQL8. DMS est un service recommandé par Google pour déplacer des charges de travail SQL depuis d'autres infrastructures vers des instances Cloud SQL gérées par Google. Nous avons choisi d'utiliser les tâches de migration de type continu, qui s'appuient sur une phase de dump initiale, puis sur une réplication primaire-secondaire durant la phase CDC. Nous avons surveillé le décalage de réplication, et lorsque celui-ci était faible, nous étions prêts à basculer de l'ancienne instance vers la nouvelle. Bien que cette condition puisse être remplie à tout moment de la journée, nous avons effectué le basculement uniquement la nuit et le week-end, afin de minimiser les perturbations du service client.
Cadre d'opérations asynchrones
Historiquement, nos mises à niveau étaient pilotées par le push_master, qui surveille en permanence les mises à niveau. Elles durent généralement environ 2 heures. Cependant, compte tenu de l'important volume de données (point 1 ci-dessus), la mise à niveau SQL devait s'étaler sur plusieurs jours. De plus, nous devions mettre à niveau près de 75 projets comportant chacun 2 instances Cloud SQL, ce qui rendait une mise à niveau manuelle fastidieuse. Nous avons décidé de mettre en place ce que nous appelons l'AsynchronousUpgradeframework pour résoudre ce problème.
À très haut niveau, il s'agit d'une machine à états. L'état actuel de la mise à niveau est stocké dans un bucket GCS, dans un fichier appelé le fichier d'état. Un tick périodique survient, charge le fichier d'état et envoie des requêtes GCP pour examiner l'état actuel de la migration. Ensuite, en fonction de ces 2 entrées, la machine à états peut mettre à jour l'état et entreprendre une action. Un exemple possible : l'état actuel des tâches de migration est « en cours », nous examinons le décalage de réplication et constatons qu'il est assez élevé, nous restons donc dans le même état. En revanche, si le décalage de réplication s'avère faible et que l'utilisation du système est basse (point 4 ci-dessus), nous décidons d'effectuer une transition d'état en appliquant un correctif à la nouvelle instance, en basculant celle-ci et en déclenchant les redémarrages et redéploiements.
Toutes les opérations effectuées par ce cadre doivent être idempotentes en cas de problèmes intermittents. Elles doivent donc laisser le système dans un état cohérent pour le prochain tick.
Avantages de MySQL8 par rapport à MySQL5
Si une comparaison détaillée des performances de MySQL8 par rapport à MySQL5 pour les charges de travail de Glean pourrait faire l'objet d'un article distinct, voici quelques premières indications :
- Des gains significatifs sur le CPU pour une même charge de travail. Par exemple, dans un cas, le CPU est passé à environ 30 %, alors qu'il oscillait initialement autour de 50 %.
- Des E/S de lecture disque réduites.
- L'utilisation de la mémoire semble similaire. Nous pensons que MySQL cherche à maintenir la mémoire autour de 85 % de la mémoire disponible.
- Nous avons également observé une bien meilleure mise en cache des requêtes similaires.
Quelques enseignements
Au cours de ce projet, nous avons appris de nombreuses choses.
- Il est difficile de réduire rapidement le décalage de réplication en cas de forte charge sur la base de données source. Nous avions initialement décidé de laisser la base source fonctionner à plein régime pendant que le réplica se mettait à jour. Nous supposions qu'en ajustant les paramètres de réplication parallèle et la sémantique de validation des transactions, nous pourrions réduire le décalage. Mais nous avons rapidement constaté que cela ne fonctionnait pas dans notre cas. Nous avons dû suspendre l'activité sur la base source.
- Temps de dump initial long : si les données sont concentrées dans quelques tables de la base source, le dump initial sera très long. Nous avons eu un cas où environ 90 % des données se trouvaient dans une seule table, sur un projet spécifique. Lors de notre première tentative, le dump initial a pris plus de 7 jours. Comme la rétention maximale du journal de réplication sur la source pouvait être de 7 jours, la tâche n'obtiendrait jamais les bonnes mises à jour. Heureusement, nous avons pu ignorer une partie de ces données grâce aux dumpFlags, puis les réexplorer une fois le basculement vers la nouvelle instance effectué.
- La mise à l'échelle avec le modèle actuel, où nous disposons d'un projet GCP distinct pour chaque client, peut s'avérer délicate pour les migrations futures. Nous devrions évoluer vers une architecture multi-tenant, avec des projets uniques regroupant davantage de clients.
Si concevoir ou utiliser un produit de recherche de premier plan vous intéresse, nous serions ravis d'échanger avec vous !






