Cloudflare a annoncé la disponibilité générale de la prise en charge de MySQL dans Hyperdrive, un service destiné aux utilisateurs de Workers pour mutualiser et réutiliser les connexions aux bases de données via le réseau de l’entreprise. Le passage de la version bêta à la disponibilité générale est intervenu après la correction d’environ 20 bugs, dont un rare problème de mise en cache des résultats de requêtes qui entraînait des réponses vides alors que des données étaient censées être présentes.
Le problème apparaissait à un taux d’environ 0,001 %, ce qui rendait sa détection dans les journaux de traçage difficile. Cloudflare a découvert que le bug ne se manifestait que lorsque la mise en cache était activée, après avoir été signalé par le client qui utilisait le plus le service MySQL pendant la phase bêta.
Comment fonctionne Hyperdrive ?
Hyperdrive maintient des connexions SQL actives et ouvertes sur le réseau de Cloudflare, puis les partage entre les requêtes Workers au lieu de créer une nouvelle connexion pour chaque requête. Le service peut également stocker les résultats des requêtes fréquentes dans la mémoire cache locale du CDN, ce qui réduit la latence et la pression exercée sur la base de données d’origine.
L’architecture du service se compose d’un nœud Client fonctionnant à proximité du Worker et d’un nœud Endpoint qui gère le pool de connexions et se trouve dans un centre de données proche de la base de données d’origine. Les deux nœuds peuvent partager le même cache lorsqu’ils fonctionnent dans le même centre de données.
Le bug concernait une différence dans le format du protocole MySQL
Hyperdrive traite MySQL depuis deux côtés différents : il fonctionne comme un serveur face au Worker et comme un client face à la base de données d’origine. Comme les capacités du protocole négociées par le Worker peuvent différer de celles qu’Hyperdrive utilise avec la base de données, le service doit reformater les messages de résultats pour les adapter au client final.
L’enquête s’est concentrée sur la manière de terminer les ensembles de résultats. Certaines bibliothèques MySQL, dont la bibliothèque mysql2 courante dans Node.js, ne prennent pas en charge la capacité CLIENT_DEPRECATE_EOF. En l’absence de cette capacité, le serveur utilise des paquets EOF, tandis que le comportement du protocole plus récent les remplace par un paquet OK à la fin d’un ensemble de résultats.
Le nœud Client mettait parfois en cache les octets après les avoir traduits pour correspondre aux capacités du Worker, tandis que le nœud Endpoint attendait une version standard dotée des capacités d’Hyperdrive. Lorsqu’un nœud lisait un résultat mis en cache par l’autre, il pouvait interpréter les messages dans un format inadapté, ce qui entraînait un EOF prématuré, un blocage ou un résultat vide.
Qu’est-ce qui a changé concrètement ?
Cloudflare a corrigé le problème en faisant en sorte que tous les nœuds écrivent dans le cache une version standard du résultat de la requête, toujours encodée selon les capacités d’Hyperdrive, quel que soit le nœud qui l’a mise en cache. Après le déploiement du correctif, le problème des lignes vides a disparu et le taux de réussite des connexions Client a atteint 99,99 %, selon Cloudflare.
L’entreprise a également corrigé d’autres problèmes apparus pendant les tests, dont une erreur d’encodage des émojis. L’utilisation de utf8 désignait en pratique utf8mb3, qui ne prend pas en charge tous les points de code Unicode sur quatre octets. Le service est passé à utf8mb4. Il réinitialisait également l’encodage après l’exécution de la commande COM_RESET_CONNECTION, car cette commande rétablit la connexion aux paramètres par défaut du serveur, qui peuvent être latin1.
Disponibilité et limites
La prise en charge de MySQL est désormais généralement disponible via le tableau de bord Cloudflare ou l’outil wrangler, et peut être utilisée avec des bases de données MySQL compatibles, notamment pour se connecter à une nouvelle base de données PlanetScale. Cette situation montre que la mutualisation des connexions et la mise en cache dans une couche intermédiaire ne dépendent pas uniquement de la validité du SQL, mais exigent également une correspondance précise entre les états du protocole et le format attendu par chaque couche.