Déploiement progressif du code de classement chez Glean

0
minutes de lecture
Déploiement progressif du code de classement chez Glean

Table des matières

Vous avez des questions ou souhaitez une démo ?

Nous sommes là pour vous aider ! Cliquez sur le bouton ci-dessous et nous vous recontacterons.

Demander une démo
Partager cet article :

Dans la recherche Glean, nous nous efforçons toujours de renvoyer les résultats les plus pertinents. Lorsque nous fusionnons des résultats issus de diverses sources — des fils de discussion Slack aux bugs Jira en passant par les documents O365 — de nombreuses dimensions permettent d'expérimenter avec nos fonctions de classement.

Pour aider à développer ces fonctionnalités, nous souhaitions des versions itératives fréquentes pour notre équipe de classement. Mais un cycle rapide peut s'avérer délicat dans le contexte d'un service à états. En particulier, nos principaux Index Servers doivent précharger d'importantes quantités de données d'index en mémoire lors de leur redémarrage. Dans bien des cas, le préchargement de ces données pouvait prendre plus de 15 minutes, ce qui nécessitait soit une interruption de service planifiée, soit une atténuation relativement complexe.

En pratique, avec cette contrainte, nous avons constaté que nous ne déployions pas les mises à jour clients aussi souvent que nous le souhaitions. Et nos ingénieurs ont découvert que leur cadence de développement était inutilement ralentie par les longs temps de redémarrage des serveurs.

Comment avons-nous résolu ce problème et progressé vers un déploiement incrémental plus rapide ?

  • Nous avons réalisé qu'une grande partie du problème était résolue si nous pouvions éviter de redémarrer notre Index Server pour recevoir les mises à jour de code dans le cas courant.
  • Heureusement, ce serveur en particulier était écrit en Java, qui dispose d'un mécanisme pour charger du code de manière dynamique. Après avoir étudié les ClassLoaders personnalisés, nous avons prototypé le chargement d'une archive Java JAR depuis Cloud Storage et l'utilisation des classes dans notre processus, sans redémarrage.
  • Même avec la possibilité de charger du code depuis Cloud Storage sans redémarrer, Java n'autorise qu'une seule implémentation pour un nom de classe donné. Cela dit, nous avons réalisé que nous pouvions ajouter le tag de version aux noms de packages de nos classes. Par exemple, pour la classe com.glean.ranking.TermInfo, nous pouvions charger un nombre illimité de versions dans le serveur si nous écrivions un outil pour réécrire et insérer le tag de version dans le nom : com.glean.ranking.release123.TermInfo, com.glean.ranking.release124.TermInfo, etc. Nous avons utilisé des bibliothèques open source (par ex. ObjectWeb ASM) pour aider à construire cet outil de remappage. Au final, nous disposions d'un script pour remapper les artefacts de build d'un tag de version spécifié et les téléverser sur le cloud en quelques secondes.
  • Avec la possibilité de charger dynamiquement plusieurs versions de code depuis Cloud Storage, il suffisait ensuite de faire circuler ces tags de version à travers le système, afin que la version ou l'expérimentation correcte soit utilisée pour une requête donnée. 

‍

Nous avons rapidement découvert les avantages de cette approche :

  • Des versions plus fréquentes et moins perturbatrices : comme les redémarrages de serveur n'étaient normalement plus nécessaires, nous avons commencé à déployer les changements de classement plus fréquemment — chaque nuit pour le déploiement interne, et chaque semaine pour les clients.
  • Expérimentation : nous avons également commencé à utiliser ce mécanisme pour les expérimentations des développeurs ; plutôt que de coordonner l'utilisation d'un cluster de développement et d'attendre un redémarrage de serveur, ils pouvaient simplement téléverser un fichier Jar et voir rapidement les résultats.
  • Versionnement robuste : les erreurs pouvaient être associées à des tags de version spécifiques, et les différentes expérimentations étaient isolées les unes des autres.
  • Prise en charge des retours en arrière : le retour en arrière d'une version problématique pouvait se faire instantanément grâce à un changement de configuration en ligne.

Comme dans toute implémentation, quelques réglages ont été nécessaires pour faire fonctionner correctement ce mécanisme. Par exemple :

  • Décider quels ensembles de packages remapper (la version initiale ne remappait pas certains packages protobuf, ce qui s'est rapidement avéré être une erreur !)
  • Mettre en cache / charger de manière appropriée pour éviter les analyses en double des fichiers Jar
  • Supprimer les récupérations parallèles pour les mêmes classes

Nous avons constaté que la première utilisation d'un tag de version donné entraîne une latence supplémentaire d'environ une seconde, en raison de la récupération depuis Cloud Storage et de la surcharge de décodage du Jar, mais que les utilisations ultérieures sont mises en cache et impossibles à distinguer d'une implémentation classique. C'est pourquoi, pour les versions de production, nous envoyons généralement une requête de préchauffage avant de changer la configuration.

Cela dit, la possibilité de charger dynamiquement de nouvelles versions et expérimentations sans redémarrer un service à états nous offre une grande flexibilité et la capacité d'itérer pour améliorer le service Glean.

Si concevoir ou utiliser un produit de recherche de premier plan vous intéresse, contactez-nous !

Découvrez l'IA d'entreprise en action

Demander une démo
Demander une démo