todos à l’aide d’une migration sqlx-cli, puis traiter des requêtes de création, de lecture, de mise à jour et de suppression depuis un petit serveur axum. Toutes les connexions utilisent TLS avec une vérification complète des certificats.
Prérequis
- Rust 1.94 ou version ultérieure. Ce guide a été testé avec Rust 1.98.1,
sqlx0.9.0,sqlx-cli0.9.0 etaxum0.8.9. - Un compte ClickHouse Cloud
psql, pour créer la base de données. Vous pouvez aussi exécuter le statementCREATE DATABASEdans la console SQL.
Créer un service ClickHouse Managed Postgres
Dans la console ClickHouse Cloud, cliquez sur New service et sélectionnez Postgres. L’instance est prête en quelques minutes. Pour une présentation pas à pas, consultez le guide de démarrage rapide.Obtenir vos informations de connexion
Cliquez sur Connect dans la barre latérale gauche de votre service. Laissez Directly sélectionné et activez Use SSL. L’URL de connexion affichée dans l’onglet url se termine désormais parsslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem, et le port est 5432.
Cliquez sur Download CA certificate. Vous pourrez également le télécharger plus tard depuis Settings → CA Certificate. Ce certificat étant propre à votre instance, le driver peut s’en servir pour vérifier qu’il communique bien avec votre serveur.
Dans ce guide, l’application comme sqlx-cli se connectent directement à Postgres sur le port 5432. Un serveur axum est un processus de longue durée, et PgPool gère son propre pool de connexions : un second pooler devant Postgres est donc inutile. Les migrations doivent toujours passer par la connexion directe. Si vous exécutez de nombreuses instances de l’application, consultez Utiliser PgBouncer.
Configurer le projet
Créez un projet et ajoutezsqlx avec le driver Postgres, le runtime Tokio et le backend TLS rustls, ainsi qu’axum et quelques crates utilitaires :
sqlx-cli avec le même backend TLS :
Configurer la connexion
Déplacez le certificat de CA que vous avez téléchargé dans le répertoire du projet, puis renommez-le enca-certificate.pem.
Créez une base de données pour l’application. Remplacez <PASSWORD> et l’hôte par les valeurs affichées dans la fenêtre modale Connect :
.env à la racine du projet, ou modifiez DATABASE_URL dans votre fichier existant, pour qu’elle pointe vers la base de données guide_rust. L’application et sqlx-cli y lisent tous deux la valeur de DATABASE_URL :
.env
sslmode et sslrootcert dans l’URL. Avec verify-full, il vérifie que le certificat du serveur est signé par la CA de votre instance et qu’il correspond au nom d’hôte. Le path sslrootcert est résolu par rapport au répertoire depuis lequel vous exécutez les commandes. Excluez .env du contrôle de version et, si votre mot de passe contient des caractères tels que @, / ou #, encodez-les en pourcentage.
Créer la table à l’aide d’une migration
Créez un fichier de migration :migrations et ajoutez-y la définition de la table :
migrations/<timestamp>_create_todos.sql
sqlx migrate run enregistre les migrations appliquées dans la table _sqlx_migrations et n’exécute que les nouvelles lors des appels suivants. Versionnez le répertoire migrations avec votre code. Pour appliquer plutôt les migrations au démarrage de l’application, appelez sqlx::migrate!().run(&pool).await? dans main, à condition que le pool utilise la connexion directe.
Créer l’API
Remplacezsrc/main.rs par un petit serveur axum qui exécute une requête par route. Dans une application existante, créez le pool de la même manière que dans main, puis ajoutez la struct Todo, les handlers et les routes à votre propre routeur :
src/main.rs
.bind sous forme de paramètres ($1), et ne sont jamais interpolées dans la string SQL. Chaque string SQL distincte n’est préparée qu’une seule fois par connexion, puis conservée dans un cache pouvant contenir jusqu’à 100 statements ; sqlx ferme ces derniers lorsqu’il les évince du cache.
Exécuter et vérifier
Démarrez le serveur :pg_stat_ssl et confirme que la session est chiffrée. Dans un second terminal, créez deux tâches, marquez la première comme terminée, puis supprimez la seconde :
-w '\n' se contente d’ajouter un saut de ligne après chaque réponse :
http://localhost:3117/todos dans votre navigateur pour afficher la liste des tâches restantes :
guide_rust puis public, puis cliquez sur la table todos. La table _sqlx_migrations, juste à côté, contient l’historique des migrations. La table todos contient la ligne restante :
Utiliser PgBouncer
Pour connecter l’application via le PgBouncer intégré, sélectionnez via PgBouncer dans la fenêtre modale Connect et utilisez le port6432 dans la variable DATABASE_URL de l’application. Le même certificat de CA reste valable. Par exemple, conservez la connexion directe dans .env pour sqlx-cli et définissez la variable au démarrage de l’application :
pg_stat_ssl indique la propre connexion de PgBouncer à Postgres, si bien que la vérification affiche none. La connexion de votre application à PgBouncer est néanmoins bien vérifiée : un certificat de CA incorrect provoque le même échec avec UnknownIssuer.
PgBouncer fonctionne en mode pool de connexions par transaction : chaque transaction peut donc s’exécuter sur une connexion Postgres différente. Avec sqlx :
- La connexion nécessite
.extra_float_digits(None), comme dansmain.rs. Par défaut, sqlx envoieextra_float_digitscomme paramètre de démarrage, et PgBouncer rejette la connexion avecunsupported startup parameter: extra_float_digits. Pour la même raison,PgConnectOptions::optionséchoue avecunsupported startup parameter in options. - Les requêtes préparées fonctionnent avec les paramètres par défaut. sqlx libère les statements qu’il évince de son cache au moyen d’un message
Closeau niveau du protocole, que PgBouncer prend en charge, y compris au sein des transactions. Ne définissez passtatement_cache_capacity(0): c’est inutile et, lorsque le cache est désactivé, sqlx prépare toujours des statements nommés mais ne les ferme jamais. - N’utilisez pas
.persistent(false)sur des requêtes exécutées en dehors d’une transaction. sqlx prépare alors un statement sans nom et l’exécute lors d’un second aller-retour, que PgBouncer peut acheminer vers une autre connexion Postgres. La requête peut alors échouer avecunnamed prepared statement does not exist, ou exécuter silencieusement le statement d’un autre client et renvoyer des résultats erronés. - Les paramètres de session définis avec
SET, y compris dans le hookafter_connectd’un pool, ne restent pas attachés à votre connexion et peuvent se propager à d’autres clients. Utilisez plutôtSET LOCALau sein d’une transaction. - Les migrations doivent passer par la connexion directe.
sqlx-cliet les macrosquery!ne peuvent pas se connecter via PgBouncer, car ils envoient systématiquementextra_float_digits.sqlx::migrate!acquiert un verrou consultatif au niveau de la session (pg_advisory_lock) et, via PgBouncer, le déverrouillage peut aboutir sur une autre connexion Postgres. Le verrou reste alors détenu sur une connexion du pool, et les migrations suivantes, y compris via la connexion directe, restent bloquées jusqu’à ce que PgBouncer ferme cette connexion.
Étapes suivantes
- Connexion : chaînes de connexion, PgBouncer et TLS
- Paramètres : paramètres de Postgres et de PgBouncer, comme
max_connections - Répliques en lecture : acheminer les requêtes en lecture seule vers une réplique à l’aide d’un second
PgPool - Sécurité : listes d’accès IP et réseau privé