Réveiller des bases de données sans connexions mortes
Les applications publiées sur Mythex, ainsi que leurs bases de données, se mettent en veille lorsque personne ne les utilise. Au réveil, une application pouvait retenir sa première requête pendant 10 à 12 secondes, parce qu'elle tentait de réutiliser des connexions à la base qui étaient mortes pendant que tout dormait. Nous donnons maintenant aux applications Spring Boot des paramètres de base de données sûrs après une mise en veille, et nous demandons à l'agent de construire les applications de n'importe quelle pile de la même manière. Sur la plateforme d'hébergement, la première requête après un réveil est passée de 12,7 secondes à 2,3 secondes.
Pourquoi les applications et les bases de données se mettent en veille
Une application Mythex publiée tourne sur une machine qui se suspend après quelques minutes d'inactivité, et sa base de données est un Postgres sans serveur qui s'endort après cinq minutes d'inactivité et se réveille à la requête suivante. C'est ce qui maintient une application calme à faible coût : vous payez pour ce que la base de données a réellement utilisé, et une application en veille ne consomme pas de calcul. Nous avons décrit l'aspect facturation dans facturer les bases de données selon ce qu'elles utilisent réellement.
Le piège, c'est que les deux se mettent en veille séparément, et qu'ils ne s'entendent pas sur la notion de connexion.
Le symptôme : une première visite lente
La plupart des applications serveur conservent un pool de connexions : un petit nombre de connexions à la base ouvertes et prêtes, pour que chaque requête n'ait pas à en ouvrir une nouvelle. C'est la bonne conception pour une application toujours active.
Voici ce qui se passe avec la mise en veille :
- L'application tourne, avec quelques connexions inactives dans son pool.
- Personne ne la visite. La machine de l'application se suspend — figée, avec son pool intact.
- La base de données s'endort et ferme son extrémité de chaque connexion.
- Un visiteur arrive. L'application se réveille exactement comme elle était, mais elle détient toujours des connexions que la base ne connaît plus.
- Le pool remet l'une de ces connexions. Il doit découvrir qu'elle est morte — en tentant de l'utiliser et en attendant — avant de l'abandonner.
Dans une application Spring Boot, la validation de ces connexions mortes bloquait la première requête pendant une dizaine de secondes avant qu'elle n'échoue avec « Connection is not available ». Pour le visiteur, le site semblait simplement figé, puis affichait peut-être une erreur.
Pourquoi les applications Spring étaient les plus touchées
Spring Boot est un cadriciel Java populaire, et il utilise par défaut un pool de connexions appelé HikariCP. Spring peut configurer ce pool à partir de paramètres, y compris le nombre de connexions inactives à conserver.
Mais Mythex fournit à chaque application sa base de données sous la forme d'une seule variable DATABASE_URL, de la forme postgresql://utilisateur:motdepasse@hôte/base. Spring ne peut pas lire directement ce format. Les applications Spring construites sur Mythex construisaient donc leur propre pool dans le code en analysant cette URL — et un pool construit à la main ignore tous les paramètres spring.datasource.* de Spring. Même si quelqu'un connaissait les bons paramètres de pool, rien ne leur permettait de prendre effet.
La correction, partie 1 : des paramètres que Spring peut utiliser
Lorsqu'un projet dispose d'une base de données, nous lui fournissons maintenant aussi des variables d'environnement que Spring lit nativement :
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEetSPRING_DATASOURCE_PASSWORD, convertis à partir deDATABASE_URL(avec SSL requis, sauf si l'URL indique le contraire).- Des paramètres de pool qui survivent à la mise en veille :
| Paramètre | Valeur | Pourquoi |
|---|---|---|
| Connexions inactives minimales | 0 | Ne rien garder ouvert entre les requêtes, donc rien ne peut périmer |
| Délai d'inactivité | 30 secondes | Fermer rapidement les connexions inutilisées |
| Durée de vie maximale | 2 minutes | Retirer chaque connexion avant qu'elle ne vieillisse |
| Délai de connexion | 5 secondes | Ne pas bloquer une requête longtemps si la base répond lentement |
Sans connexion inactive conservée, une application réveillée ouvre une nouvelle connexion au lieu de passer en revue des connexions mortes.
Lorsque ces variables sont présentes, Spring configure lui-même le pool, et les paramètres s'appliquent. Tout ce que le projet a défini lui-même l'emporte toujours ; nous ne complétons que ce qui manque. Les applications qui ne sont pas en Spring ignorent ces variables.
Le détail qui a failli ne rien changer
Spring associe les variables d'environnement à ses paramètres selon une règle facile à mal appliquer. Le paramètre minimum-idle doit s'écrire SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — tirets supprimés, mots accolés. L'écrire SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, ce qui semble plus naturel, correspond à un autre paramètre inexistant (minimum.idle) et est ignoré sans avertissement.
C'est le genre d'erreur qui passe toutes les relectures et ne fait rien en production. Un test vérifie donc à la fois que les valeurs sont définies et qu'aucune variable n'utilise la forme séparée par des tirets bas.
La correction, partie 2 : toutes les autres piles
Spring n'est pas le seul cadriciel à avoir un pool, et nous ne pouvons pas préconfigurer chaque bibliothèque dans chaque langage. L'agent Mythex — l'IA qui écrit votre application — reçoit donc désormais une consigne permanente pour toute pile : les applications publiées et leurs bases de données se mettent en veille lorsqu'elles sont inactives, si bien qu'une connexion gardée ouverte peut être morte à la requête suivante. Il doit :
- ne garder aucune connexion inactive ouverte à la base, ou vérifier chacune avant de l'utiliser,
- réessayer une fois en cas d'erreur de connexion, et
- utiliser les paramètres de base de données fournis par la plateforme dans l'environnement, plutôt que de construire son propre pool en analysant
DATABASE_URL.
Ce dernier point referme la boucle avec la partie 1 : une application construite sur les paramètres fournis adopte automatiquement la configuration adaptée à la mise en veille.
Le résultat
Mesuré sur la plateforme d'hébergement où nous exécutons les applications publiées, la première requête après un réveil est passée de 12,7 secondes à 2,3 secondes.
Ce que nous en avons retenu
- Chaque couche qui se met en veille doit s'entendre sur ce qui survit. Une application figée et une base endormie ont chacune fait un choix raisonnable. Ensemble, l'application se réveillait en détenant un état qui n'était plus vrai.
- Les valeurs par défaut conçues pour des serveurs toujours actifs ne conviennent pas aux applications qui descendent à zéro. Garder les connexions au chaud est une bonne idée, jusqu'à ce que tout ce qui les entoure refroidisse.
- Fournissez aux cadriciels leurs données dans leur propre format. Une seule URL était simple pour nous, mais forçait chaque application Spring à bricoler un pool qui ignorait sa propre configuration.
- Testez qu'un paramètre est écrit comme le cadriciel le lit. Une bonne valeur sous le mauvais nom ne fait rien, en silence.
Si vous découvrez le fonctionnement des bases de données sur Mythex, consultez la documentation sur les bases de données et notre guide sur ce qu'est Postgres.