Base de données dédiée vs mutualisée : impact réel sur la performance et l'isolation
Une base de données mutualisée ne veut pas dire que vos données se mélangent avec celles d'un autre client. Elle veut dire que votre base tourne sur un serveur Postgres partagé avec d'autres bases. La vraie question n'est donc pas « mes données sont-elles isolées ? » mais « mes ressources le sont-elles ? ». CPU, mémoire, connexions et débit disque peuvent se dégrader à cause d'un voisin bruyant même quand chaque tenant a sa propre base, sa propre table, ses propres policies.
Cet article compare les modèles de tenance Postgres les plus documentés (schéma partagé, base par tenant, cluster dédié, aussi appelés database-per-tenant vs shared database), explique le mécanisme du noisy neighbor, puis détaille comment Aurabase implémente son propre modèle à deux paliers, vérifié dans le code du provisioner. Pour la méthodologie que nous appliquons avant de publier un chiffre de performance, voir notre méthodologie de benchmark backend.
Si vous cherchez la question de la fuite de données entre deux clients (RLS, policies, service_role), ce n'est pas l'angle de cet article : notre comparatif RLS et base dédiée par projet couvre cette isolation logique en détail. Ici, on parle de ressources physiques : CPU, IO, connexions, cache.
- Une base mutualisée n'est pas forcément un schéma partagé : Aurabase donne à chaque projet sa propre base Postgres, même sur ses paliers standards, en ne mutualisant que le cluster.
- Le
noisy neighbordégrade des ressources physiques (CPU, IOPS, connexions, autovacuum), pas la confidentialité des données : la RLS ne le résout pas, ce n'est pas son rôle. - Le provisioner Aurabase route vers exactement deux architectures, vérifié dans le code :
FullyDedicated(cluster CNPG entier réservé à un projet, palier entreprise) ouSharedClusterDedicated(base dédiée sur le cluster CNPG de l'organisation, jamais partagé avec une autre organisation). - Un cluster de flotte Aurabase a un seuil de capacité observé par défaut de 1000 bases par cluster, configurable, au-delà duquel la recommandation est de migrer vers un cluster dédié.
- Le bon choix dépend de vos contraintes réelles (conformité, prévisibilité du trafic, budget), pas d'un réflexe « le dédié est toujours mieux ».
Trois modèles de tenance Postgres, du plus mutualisé au plus isolé
La documentation officielle de Microsoft sur l'architecture des applications SaaS multi-tenant distingue trois modèles de tenance, généralement nommés Silo (ressources dédiées par tenant), Pool (ressources entièrement partagées) et Bridge (un mélange des deux, certains tenants isolés, d'autres mutualisés). Ces trois modèles s'appliquent directement à Postgres, à l'échelle du schéma, de la base ou du cluster entier.
Concrètement, pour un backend Postgres, ça donne trois architectures distinctes. Le schéma partagé (une seule base, une colonne tenant_id, des policies RLS qui filtrent les lignes) est le modèle Pool le plus répandu dans les guides multi-tenant : économique, mais la frontière entre deux clients devient une expression SQL évaluée table par table. La base par tenant sur un cluster mutualisé est un modèle Bridge intermédiaire : chaque tenant a sa propre base Postgres (une vraie commande CREATE DATABASE), mais plusieurs bases cohabitent sur le même cluster physique, donc partagent CPU, IO et connexions. Le cluster entièrement dédié par tenant est le modèle Silo complet : ressources CPU, RAM et IO totalement isolées, généralement réservé aux tenants à fort enjeu de conformité ou de charge.
Terminologie Silo / Pool / Bridge : documentation officielle Microsoft, patterns d'architecture SaaS multi-tenant (Azure Architecture Center).
Le modèle intermédiaire, base par tenant sur cluster mutualisé, est souvent absent des guides qui présentent le choix comme binaire entre « une seule base pour tout le monde » et « un serveur par client ». C'est pourtant celui que retient Aurabase par défaut, détaillé plus bas.
Le choix entre ces trois modèles se pose à chaque décision d'architecture multi-tenant, pas seulement chez un fournisseur de BaaS : une équipe qui construit elle-même son backend SaaS sur Postgres géré (RDS, Cloud SQL, ou une instance auto-hébergée) fait exactement le même arbitrage, avec les mêmes mécanismes de contention en jeu une fois plusieurs clients placés sur la même instance physique.
Le noisy neighbor : ce qui se dégrade quand les ressources sont partagées
Un noisy neighbor (voisin bruyant) est un tenant qui consomme une part disproportionnée des ressources partagées d'une infrastructure, au détriment des autres locataires du même serveur. Le terme vient du cloud public, mais s'applique directement à un cluster Postgres mutualisé : une base peut dégrader les performances des autres sans jamais toucher à leurs données.
Six mécanismes reviennent le plus souvent en production :
- Contention CPU : une requête coûteuse (jointure sans index, tri massif) consomme des cycles CPU que le noyau partage entre toutes les bases actives du cluster.
- Contention IOPS : une sauvegarde, un
VACUUM FULLou un import massif saturent le débit disque du cluster, ralentissant les lectures et écritures des autres bases. - Épuisement des connexions :
max_connectionsplafonne le nombre de connexions actives au niveau du cluster entier, pas par base. Une base qui en ouvre trop réduit la marge des autres. - Contention autovacuum : l'autovacuum tourne avec un nombre limité de workers par cluster ; une base à fort taux d'écriture peut retarder le nettoyage des tables d'une autre base.
- Éviction du cache :
shared_buffersest une mémoire unique pour tout le cluster ; une base au working set large peut évincer les pages en cache d'une base voisine plus petite. - Fenêtres de maintenance partagées : sauvegarde, bascule de réplica ou montée de version majeure s'appliquent au cluster entier, pas base par base.
Schéma structurel, pas un résultat de mesure : aucun chiffre de performance comparatif publié à ce jour pour ces deux topologies.
Le budget de connexions est souvent le symptôme le plus visible en production, avant même la latence. C'est le sujet détaillé de notre guide de tuning max_connections et de notre comparatif PgBouncer, Supavisor et PgCat.
Un pooler en mode transaction (PgBouncer, Supavisor, PgCat) atténue l'épuisement des connexions, mais ne supprime pas la contention CPU ni la contention IOPS : il réutilise des connexions serveur existantes, il n'ajoute ni cœur CPU ni débit disque supplémentaire au cluster. Notre article sur le mode transaction pooling détaille ce que ce mode change réellement, et ce qu'il ne change pas.
RLS isole les données, pas les ressources
La Row-Level Security résout un problème différent : elle empêche une requête de lire ou modifier les lignes d'un autre tenant, au niveau logique. Elle ne réserve aucun cycle CPU, aucun slot de connexion, aucun débit disque à un tenant précis.
Deux tenants peuvent avoir des policies RLS parfaitement étanches et se dégrader mutuellement au même instant : le noisy neighbor est un problème de ressources physiques, pas de droits d'accès. Confondre les deux mène à une fausse impression de sécurité opérationnelle une fois la RLS en place.
service_role, frontière entre projets côté sécurité), voir notre article dédié : RLS et base dédiée par projet, le choix d'isolation multi-tenant d'Aurabase. Cet article-ci reste sur le plan des ressources physiques.Le modèle tiéré d'Aurabase, vérifié dans le code
Le code du provisioner (services/aura-provisioner) documente exactement deux architectures possibles pour un projet Postgres actif, depuis une consolidation du provisioning que le code désigne comme la Tâche 12 : FullyDedicated et SharedClusterDedicated. Les anciens modèles à granularité schéma ont été retirés du chemin de provisioning.
Le palier enterprise déclenche FullyDedicated : un cluster CNPG entier, réservé à ce seul projet. Tous les autres paliers (free, pro, team) routent vers SharedClusterDedicated : une base Postgres project_<uuid> à part entière, sur le cluster CNPG de l'organisation du projet. Ce n'est donc pas un schéma partagé : même sur un plan standard, votre base est une base Postgres complète, pas une ligne parmi d'autres dans une table commune. Ce qui est mutualisé, c'est le cluster (CPU, RAM, disque, connexions), pas la base elle-même.
Le cluster CNPG d'une organisation est créé au provisioning de son premier projet Postgres et n'accueille jamais un projet d'une autre organisation, un choix de conception verrouillé au niveau du code (org_cluster.rs, verrou consultatif Postgres par organisation à la création). Le seul voisin bruyant possible sur le palier mutualisé d'Aurabase est donc un autre projet de votre propre organisation, jamais celui d'un client tiers.
Vérifié dans services/aura-provisioner/src/{provisioning.rs, fleet.rs, org_cluster.rs} et docker/Postgres.CNPG.Dockerfile, code au 24 août 2026.
Ce seuil de 1000 bases par cluster n'est pas une limite dure : c'est un repère d'observabilité qui déclenche une recommandation de migration vers FullyDedicated, pas un blocage automatique. Il ne pilote plus aucune décision de placement, un seul cluster étant désormais possible par organisation.
Chaque cluster, dédié ou de flotte, expose un Pooler CNPG (PgBouncer) qui absorbe une partie de la pression sur les connexions actives, dans les deux topologies. Ce que ce pooler change réellement pour la contention de ressources est détaillé plus bas.
Le dimensionnement CPU/RAM d'un cluster mutualisé n'est pas non plus uniforme entre organisations : il dérive du palier de l'organisation via une fonction dédiée (FleetSizing::from_org_plan, vérifiée dans org_cluster.rs), et non d'une taille unique appliquée à tous les paliers. Une organisation au palier team ne dimensionne pas son cluster de la même façon qu'une organisation au palier free.
Ces deux architectures tournent sur PostgreSQL 16, pas la version 17, vérifié dans le Dockerfile de l'image CNPG utilisée en production. Ce choix de version a ses propres implications de tuning, détaillées dans notre comparatif Postgres 16 vs 17 vs 18.
Quand la mutualisation suffit, quand le dédié devient nécessaire
Pour les projets soumis à une obligation contractuelle d'isolation physique documentée, nos pages DPA et conformité détaillent ce que couvre chaque palier.
Le revers du modèle base-par-tenant, que soulignent plusieurs outils de gestion de migrations de schéma comme Bytebase, est opérationnel plus que technique : chaque migration doit s'appliquer et se vérifier sur chaque base, une par une, même quand elles cohabitent sur le même cluster. Un cluster entièrement dédié n'élimine pas ce coût, il l'ajoute même : une migration par cluster à surveiller indépendamment, plutôt qu'une seule.
Des ressources spécialisées en architecture logicielle multi-tenant, comme CodeOpinion, présentent régulièrement cette approche intermédiaire (base par tenant sur infrastructure mutualisée) comme un compromis raisonnable entre le schéma partagé et le cluster entièrement dédié, plutôt qu'un choix binaire entre les deux extrêmes.
Passer du mutualisé au dédié n'impose pas de réécrire un schéma ni de changer de moteur : dans les deux cas, c'est du Postgres, avec la même chaîne pg_dump / pg_restore que celle décrite dans notre guide de migration Supabase vers Aurabase. Le changement de palier reste une opération de bascule, pas une réécriture d'application.
Questions fréquentes
Ce qu'il faut retenir
Base dédiée et base mutualisée ne s'opposent pas sur la sécurité des données : les deux modèles peuvent isoler correctement un tenant d'un autre au niveau logique. Ils s'opposent sur les ressources physiques (CPU, IOPS, connexions, cache, fenêtres de maintenance). C'est ce plan-là qui définit un noisy neighbor, pas une policy RLS mal écrite.
Le modèle d'Aurabase, vérifié dans le code du provisioner, retient par défaut un compromis intermédiaire : une base Postgres dédiée par projet, sur un cluster mutualisé mais strictement réservé à une seule organisation, avec un cluster entièrement dédié réservé au palier entreprise. Le bon choix dépend de vos contraintes réelles, pas d'un réflexe où le dédié serait toujours la meilleure option.