Hacker News adore les histoires de réécriture. L’étincelle de cette semaine : une base de données compatible Postgres, réécrite en Rust, affirmant réussir 100 % des tests de régression de Postgres. Impressionnant. Mais si vous êtes le CTO responsable des RPO/RTO, vous savez que 100 % d’une suite de tests n’est pas 100 % de la production. Votre rôle n’est pas d’applaudir la sûreté mémoire — c’est de maintenir le revenu qui rentre et des données sans histoires. Ce billet vous propose une carte des risques concrète et assumée avant même d’envisager d’orienter du trafic de production vers un Postgres-en-Rust flambant neuf.
Ce que « 100 % des tests de régression » signifie réellement
La suite de régression de Postgres est un trésor : elle vérifie la syntaxe SQL, le comportement du planificateur et de l’exécuteur, les types, les index, certaines sémantiques MVCC, et une longue traîne de fonctionnalités cœur. La réussir, c’est le ticket d’entrée pour la compatibilité protocolaire et SQL.
Mais ce n’est pas un proxy de maturité opérationnelle. Ce que ces tests couvrent très peu :
- Durabilité en cas de vraie coupure électrique : comportements de fsync selon les systèmes de fichiers (ext4, XFS, ZFS), temporisation du group commit, détection de pages déchirées, limites de segments WAL.
- Cas limites de réplication : comportements de quorum en réplication sync/async, changements de timeline, réplicas en cascade, standby retardé, et mécanismes de fencing lors du failover.
- Vacuum et contrôle du bloat en charge : interactions d’autovacuum à fort débit d’écritures, HOT updates, justesse de la visibility map sur des semaines de charge.
- Chemins de mise à niveau : mises à niveau sur place via les sémantiques de pg_upgrade, migrations de catalogue entre versions majeures, chaînes de migration logique.
- Invariants d’observabilité : stabilité et précision des vues
pg_stat_*à forte concurrence, hooksauto_explain, sémantiques de remise à zéro des statistiques.
Réussir la suite vous dit que le moteur peut se faire passer pour Postgres. Cela ne vous dit pas ce qui se passe à 02:13 un dimanche lors d’une partition réseau en rouleau, quand votre primaire subit un blocage fsync et que votre logique de failover devient nerveuse.
La compatibilité va bien au-delà du SQL
Si vous avez été d’astreinte pour Postgres, vous savez que la « base de données » est un écosystème, pas juste un binaire serveur. Avant même de tester une réécriture en Rust en labo, inventoriez les fonctionnalités que vous utilisez réellement :
- Extensions :
pg_stat_statements,pgcrypto,pg_trgm,hstore, PostGIS, Timescale, HypoPG. La réécriture supporte-t-elle l’ABI C de Postgres pour les extensions ? Sinon, quels équivalents existent et quelle est leur maturité ? - Logical decoding : plugins de décodage (wal2json, variantes de pgoutput), intégration Debezium, sémantiques des replication slots, interactions avec vacuum.
- Foreign Data Wrappers (FDW) : utilisez-vous des FDW S3, Kafka, ou inter-BD ? Comment la réécriture les gère-t-elle (le cas échéant) ?
- Spécificités du protocole et de l’auth : comportement au niveau du fil avec PgBouncer (pooling Tx vs Session), authentification SCRAM-SHA-256, GSSAPI/Kerberos, politiques de renégociation SSL.
- Outils de DDL et de migration : Flyway, Liquibase, Django, Rails, Prisma, TypeORM. Quelque chose suppose-t-il des comportements autour du DDL transactionnel, des advisory locks ou de
search_path?
Faites un tableau simple en deux colonnes pour votre stack : « fonctionnalité utilisée » vs « statut dans la réécriture Rust ». Toute case rouge sur les extensions, le logical decoding ou la HA doit arrêter vos ambitions de production.
La maturité opérationnelle représente 80 % de la valeur de Postgres
Il y a dix ans, faire tourner Postgres en production, c’était décrocher ses galons. Aujourd’hui, l’écosystème rend la chose presque ennuyeuse — si vous restez sur les sentiers battus :
- HA/Failover : Patroni, Stolon, repmgr. Le moteur Rust s’intègre-t-il avec eux ? Sinon, qu’est-ce qui orchestre l’élection du leader, le fencing et le bootstrap des réplicas ?
- Backup/PITR : sauvegardes complètes + archivage WAL avec pgBackRest ou WAL-G. Les formats d’archives et les mécaniques de restauration sont-ils compatibles ? Pouvez-vous démontrer une récupération au point dans le temps vers un timestamp arbitraire ?
- Mises à niveau : existe-t-il un équivalent de
pg_upgradeou devrez-vous faire des migrations logiques à chaque version majeure ? - Observabilité :
pg_stat_activity,pg_locks,pg_stat_replication,pg_stat_wal,pg_stat_io,auto_explain, échantillonnage de requêtes, hygiène de log_line_prefix. Vos dashboards et alertes actuels peuvent-ils se brancher sans changement ? - Vacuum, bloat et stockage : justesse de la visibility map, stratégie de freeze, détection et mitigation du bloat des relations. Obtenez-vous la parité avec
pg_stat_all_tables?
Si votre réponse est « on construira nos propres operators et nos flux de sauvegarde », budgétez en conséquence. Vous échangez une décennie de mémoire collective durcie par la communauté contre un runbook sur mesure tout neuf.
Les promesses de performance exigent des comparaisons à périmètre constant
La sûreté mémoire de Rust est un gain. Elle vous dit ce qui n’arrivera pas (use-after-free), pas ce qui arrivera (latence). Méfiez-vous des graphiques sélectionnés. Définissez vos étalons :
- Profil de charge : OLTP (petites lignes, index chauds), requêtes de tableaux de bord très lecture, scans analytiques ? Utilisez des mixes représentatifs, pas des fantasmes
pgbench -S. - SLO de latence : p50 et p99 sous une concurrence réaliste. Suivez les queues pendant les checkpoints, les runs d’autovacuum et les événements de failover.
- Parité fonctionnelle sous charge : JIT, requête parallèle, bitmap heap scans, pression sur work_mem, débordement des tris sur disque, group commit, compromis synchronous_commit.
- Matériel et FS : mêmes NVMe, même système de fichiers, mêmes options de montage (barriers, noatime), même kernel. Fixez l’affinité CPU, isolez les IRQ, désactivez le turbo si vous êtes sérieux.
Fixez des seuils durs. Par exemple : « le moteur Rust doit maintenir un p99 dans un facteur 2 de notre baseline Postgres tunée à 2× notre QPS actuel, avec zéro delta de justesse observé sur 7 jours, et un RTO de failover ≤ 90 secondes. » S’il n’atteint pas cela avec de la marge, vous achetez du risque, pas de la performance.
Correction des données sous contrainte : le seul benchmark qui compte
La plupart des désastres ne ressemblent pas à des crashs ; ils ressemblent à des progrès partiels. C’est là que les moteurs de bases gagnent leurs galons. Évaluez la réécriture avec une approche à la jepsen :
- Boucles de crash sur des points chauds d’écriture :
kill -9du processus pendant le flush du WAL, coupez l’alimentation pendant les checkpoints, répétez sous charge. Au redémarrage, voyez-vous la détection de pages déchirées et une relecture cohérente ? - Intégrité du WAL : segments corrompus, archivage partiel de segments, idempotence archive/restauration, branchement de timeline. Pouvez-vous restaurer à N-1 transactions de manière fiable ?
- Vérité de la réplication : un replica synchrone qui bloque le primaire, un replica asynchrone qui prend > 1 heure de retard, partitions réseau. Les acquittements d’écriture sont-ils alignés avec votre contrat
synchronous_standby_names? - Checksums et vérification : checksums de pages activés, scrubbing en arrière-plan, équivalents de
pg_checksums, chemins de détection proactifs dans les logs et métriques.
Être rapide sur des happy paths est facile. Être correct quand le kernel ment sur la durabilité, que votre SAN fait des caprices et que quelqu’un trébuche sur une PDU, c’est difficile.
Une trajectoire d’adoption pragmatique si vous voulez quand même essayer
Si vous tenez à test-drive un Postgres en Rust, ne commencez pas par remplacer votre primaire. Menez un programme structuré :
- Sélection par rayon d’explosion : choisissez une charge à faible risque et faible empreinte fonctionnelle — analytique interne majoritairement en lecture ou un nouveau microservice à schéma simple. Évitez PostGIS, la compression de séries temporelles ou des triggers lourds.
- Construisez une matrice de compatibilité : listez chaque fonctionnalité utilisée (extensions, auth, CDC, FDW) face au support documenté de la réécriture. Code-couleur : vert/jaune/rouge. Arrêtez si vous voyez du rouge sur la CDC ou la HA.
- Répliquez votre trafic réel : faites un dual-write d’un petit % des requêtes de production vers les deux bases (ou rejouez des traces de production). Stockez des hash de résultats et comparez. Conditionnez la promotion à zéro delta de justesse pendant 7–14 jours.
- Test de parité CDC : si votre stack utilise Debezium ou des consommateurs en aval, branchez-les sur le moteur Rust. Vérifiez l’absence d’événements manqués ou réordonnés, surtout sous agitation de DDL.
- Exercices de Backup/PITR : prenez une sauvegarde de base, archivez le WAL et effectuez une restauration chronodatée à T-5 minutes. Vérifiez les comptes de lignes, checksums logiques et invariants au niveau applicatif.
- Game day HA : forcez un crash du primaire en pleine charge, validez RTO/RPO de failover selon vos SLO, et confirmez que les clients (via PgBouncer) se reconnectent sans tempête d’erreurs.
- Portes de déploiement : promouvez vers un seul tenant ou environnement de production à faible risque après 2 semaines consécutives propres. Gardez une voie de rollback immédiate via
pg_dumpou migration logique retour vers le Postgres standard. - Plan de sortie documenté : décidez dès maintenant comment vous retirerez (dump/restore, copie logique). Validez-le sur un dataset non trivial avant de livrer quoi que ce soit face aux clients.
Cadrez cela dans le temps. Comptez 6–8 semaines de double-exploitation et 2–3 mois-ingénieur pour atteindre une décision go/no-go avec confiance. Moins que ça, c’est du théâtre.
Où une réécriture en Rust peut briller aujourd’hui
- Déploiements edge ou embarqués : si le moteur offre une empreinte plus petite ou un meilleur démarrage à froid, cela peut être idéal pour des caches d’inférence locaux ou des apps offline-first.
- Contraintes fortes de supply chain et de sûreté mémoire : des environnements réglementés qui valorisent la sûreté mémoire et une codebase Rust moderne peuvent accepter des compromis opérationnels pour une surface plus étroite et plus sûre.
- Tranches de features greenfield : un service interne avec des schémas simples et un trafic modeste peut servir de terrain d’essai sans enlacer vos chemins de revenu cœur.
Aucun de ces cas ne devrait être votre système de facturation ni votre référentiel d’identités clients.
Quand dire non pour l’instant
- Déploiements très dépendants des extensions (PostGIS, Timescale, extensions C maison). Sans parité d’ABI, vous passerez des trimestres à remplacer des composants mûrs et supportés par des sosies.
- HA multi-région avec des RPO serrés. La réplication cross-region, le fencing à la promotion et l’évitement du split-brain sont des cicatrices de guerre qu’on ne veut pas gagner deux fois.
- Pipelines CDC à haut volume alimentant l’analytique ou la recherche. Les cas limites du logical decoding sont l’endroit où se cachent les bugs de justesse.
- Charges réglementées exigeant des contrôles documentés, une crypto validée FIPS, des playbooks de backup/restore déterministes et une observabilité compatible avec les audits.
Budgétez le coût réel
Les nouveaux moteurs ne remplacent pas des lignes budgétaires ; ils en créent. Ordre de grandeur pour une vraie évaluation (pas un week-end chauffé par un blog) :
- Engineering : 2–3 mois-ingénieur pour l’infra, les tests et l’observabilité. Ajoutez 1 SRE familier de votre Postgres actuel pour éviter les faux équivalents.
- Tooling : écrire ou adapter des operators, scripts de backup, dashboards. Comptez 1–2 semaines pour atteindre la parité avec vos alertes actuelles.
- Temps de chaos : au moins deux game days (crash/failover et restore/PITR). Allouez 6–8 heures chacun avec les parties prenantes présentes.
- Risque d’astreinte : le premier trimestre en production entraîne généralement 2–3 alertes supplémentaires jusqu’à stabilisation des runbooks. Intégrez ce stress dans votre décision.
Si un fournisseur vous vend cela, demandez-lui de cofinancer ou de doter en personnel les tests. S’il refuse, c’est un signal.
L’angle nearshore : louez de la puissance de test, pas des héros
Ce type d’évaluation est parfait pour un pod nearshore : répétitif, discipliné, time-boxé et mesurable. Avec 6–8 heures de chevauchement du Brazil aux US et un avantage coût de 20–30 % par rapport aux prestataires US, vous pouvez mobiliser une petite escouade pour :
- Construire la matrice de compatibilité et les harnais de test.
- Mettre en place en parallèle les stacks HA, backup et observabilité.
- Exécuter les comparaisons dual-write et les diffs de justesse sur des relectures de trafic réel.
- Automatiser les game days : coupures d’alimentation, boucles
kill -9et exercices PITR programmés.
La sortie attendue doit être ennuyeuse : dashboards au vert, diffs propres, et runbooks qu’un astreint à moitié endormi peut suivre à 2 h du matin.
En résumé
Rust n’est pas le sujet. La justesse des données et la besogne opérationnelle le sont. Une réécriture de Postgres qui réussit les deux gagnera sa place avec le temps. D’ici là, traitez « 100 % des tests de régression » comme une invitation à évaluer — pas une permission de migrer. Menez un programme structuré, étagez vos risques et exigez des résultats ennuyeux avant de bouger quoi que ce soit portant le nom d’un client.
Points clés
- Réussir la suite de régression de Postgres est nécessaire mais très loin d’être suffisant pour la production.
- Inventoriez extensions, CDC, FDW, auth et tooling ; toute case rouge dans votre matrice est un stop.
- La maturité opérationnelle (HA, PITR, mises à niveau, observabilité, hygiène de vacuum) représente 80 % du vrai travail.
- Définissez des seuils de performance sur p50/p99 sous une charge et un chaos réalistes, pas des microbenchmarks happy-path.
- Les tests de type jepsen sur crash, WAL et réplication sont là où apparaissent les bugs de justesse — exécutez-les.
- Adoptez via des pilotes à faible rayon d’explosion, du dual-writing et des portes de déploiement bornées dans le temps ; gardez un plan de sortie documenté.
- Dites « pas encore » pour les charges riches en extensions, la multi-région, centrées CDC ou réglementées.
- Comptez 2–3 mois-ingénieur pour une évaluation sérieuse ; envisagez un pod nearshore pour contenir coût et planning.