🔝 Retour au Sommaire
Chapitre 20 — Cas d'Usage et Architectures · §20.4 Architecture multi-tenant
Niveau : Avancé
Version de référence : MariaDB 12.3 LTS
Le pattern schéma par locataire (schema per tenant) occupe le terrain intermédiaire du continuum présenté en §20.4 : chaque locataire conserve son propre schéma (son jeu de tables), mais de nombreux schémas de locataires partagent une même instance MariaDB. On parle souvent de modèle pont (bridge), à mi-chemin entre le silo (§20.4.1) et le pool à schéma partagé (§20.4.3).
L'idée directrice est de combiner une isolation logique (les données de chaque locataire vivent dans un schéma distinct) avec une consolidation physique (une seule instance héberge l'ensemble). On obtient ainsi une meilleure densité que le silo, tout en gardant une séparation plus nette que dans un schéma entièrement partagé.
Ce pattern mérite une mise au point indispensable pour qui vient de PostgreSQL ou de SQL Server. Dans ces systèmes, une base de données contient plusieurs schémas : « schéma par locataire » y désigne alors une seule base abritant N schémas, un par locataire — un niveau intermédiaire réellement distinct de « base par locataire ».
Sous MariaDB (comme sous MySQL), il n'en va pas ainsi : CREATE SCHEMA est un synonyme de CREATE DATABASE, et il n'existe pas de niveau « schéma à l'intérieur d'une base ». En conséquence, « schéma par locataire » se traduit concrètement, sous MariaDB, par une base de données distincte par locataire, toutes hébergées sur la même instance.
La différence avec le pattern « base par locataire » (§20.4.1) ne tient donc pas au mécanisme — c'est le même — mais à l'emphase :
| Base par locataire (§20.4.1) | Schéma par locataire (§20.4.2) | |
|---|---|---|
| Mécanisme | Une base par locataire | Une base par locataire (identique) |
| Emphase | Isolation, jusqu'à l'instance dédiée | Consolidation sur une instance mutualisée |
| Densité | Faible | Moyenne |
| Voisin bruyant | Neutralisé (instance dédiée) | Possible (instance partagée) |
Garder cette équivalence à l'esprit évite bien des malentendus lors de la conception.
Le modèle pont cherche le meilleur des deux mondes voisins :
- Densité supérieure au silo : une seule instance hébergeant de nombreux locataires réduit le nombre de serveurs, le coût par locataire et la charge d'exploitation par rapport à des instances dédiées.
- Isolation logique préservée : chaque locataire ayant son propre schéma, le cloisonnement repose sur la frontière de schéma et sur les privilèges (
GRANT ... ON tenant_x.*). Un utilisateur de locataire ne peut atteindre les données d'un autre schéma. - Pas de filtrage applicatif systématique : contrairement au schéma partagé (§20.4.3), nul besoin d'ajouter une clause
WHERE tenant_id = ?à chaque requête : la séparation est portée par le schéma lui-même, ce qui réduit le risque d'erreur d'isolation. - Opérations par locataire toujours possibles : sauvegarde et restauration ciblées par schéma (
mariadb-dumppar base, chapitre 12), suppression nette d'un locataire (DROP DATABASE). - Personnalisation par locataire : chaque schéma peut accueillir des variations de structure propres à un client.
La mutualisation de l'instance fait réapparaître des contraintes que le silo « instance dédiée » avait écartées :
- Retour du voisin bruyant : tous les locataires d'une instance se partagent CPU, mémoire et I/O. Un locataire très actif peut dégrader les performances des autres.
- Point de défaillance partagé : une panne de l'instance affecte d'un coup tous les locataires qu'elle héberge.
- Migrations de schéma démultipliées : comme dans le silo, chaque locataire possédant son propre jeu de tables, toute évolution de schéma doit être appliquée à tous les schémas de l'instance.
- Plafond du nombre de schémas : c'est la contrainte la plus spécifique de ce modèle, détaillée plus loin — une instance ne peut héberger qu'un nombre limité de schémas avant que la gestion des métadonnées ne devienne pénalisante.
En résumé, ce pattern offre moins d'isolation que le silo, mais une gestion plus simple et plus dense ; et plus d'isolation que le schéma partagé, mais avec une limite de capacité par instance.
L'intégration d'un locataire crée son schéma et son utilisateur dédié sur l'instance partagée. Le mécanisme est identique à celui du silo (§20.2.1, §20.4.1) ; la différence est que toutes ces bases cohabitent sur la même instance.
-- Sur l'instance mutualisée : un schéma (= une base) par locataire
CREATE DATABASE tenant_acme;
CREATE DATABASE tenant_globex;
-- Chaque locataire a son utilisateur, limité à son seul schéma
CREATE USER 'acme_app'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret_acme');
GRANT ALL PRIVILEGES ON tenant_acme.* TO 'acme_app'@'%';
CREATE USER 'globex_app'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret_globex');
GRANT ALL PRIVILEGES ON tenant_globex.* TO 'globex_app'@'%';Une couche de routage associe chaque locataire à son schéma (et, lorsqu'on répartira plus tard les locataires sur plusieurs instances, à l'instance correspondante). À l'exécution, l'application sélectionne le schéma du locataire, soit en se connectant avec l'utilisateur dédié, soit en basculant de base (USE tenant_acme) au sein d'une connexion. La mutualisation de l'instance permet un pooling de connexions (chapitre 17) plus efficace que dans un silo dispersé sur de nombreuses instances.
- Migrations : on itère sur l'ensemble des schémas de l'instance à l'aide d'outils automatisés (Flyway, Liquibase — §16.8), avec un suivi de l'état par locataire.
- Sauvegardes : on peut sauvegarder par schéma avec
mariadb-dump(restauration ciblée d'un locataire), ou réaliser une sauvegarde physique de toute l'instance avec Mariabackup (§12.3) — qui couvre tous les locataires en une seule opération, un avantage pratique de la consolidation.
C'est la contrainte qui mérite le plus d'attention dans ce modèle. Chaque schéma de locataire réplique l'intégralité du jeu de tables de l'application. Avec N locataires et M tables par locataire, l'instance porte N × M tables. Ce nombre peut vite atteindre plusieurs dizaines ou centaines de milliers de tables.
Cette prolifération pèse sur plusieurs ressources du serveur :
- Le nombre de fichiers : avec
innodb_file_per_table, chaque table possède son propre fichier.ibd. Multiplier les tables multiplie les descripteurs de fichiers, d'où l'importance deopen_files_limitetinnodb_open_files. - Les caches de tables :
table_open_cacheettable_definition_cachedoivent être dimensionnés en conséquence, faute de quoi le serveur passe son temps à ouvrir et refermer des tables. - Les requêtes sur
INFORMATION_SCHEMA: énumérer ou interroger les métadonnées de dizaines de milliers de tables devient coûteux, ce qui affecte les outils d'administration et de supervision.
Il existe donc un plafond pratique au nombre de locataires hébergeables sur une seule instance. Ce plafond se repousse par le réglage (chapitre 11) des variables ci-dessus, mais ne disparaît jamais. C'est précisément cette limite qui distingue le « schéma par locataire » du schéma partagé (§20.4.3), où un nombre quelconque de locataires tient dans un jeu de tables unique.
Lorsqu'une instance approche de son plafond, on répartit les schémas de locataires sur plusieurs instances — une forme de partitionnement des locataires par serveur, le catalogue de routage assurant le suivi du placement de chacun. On peut ainsi croître horizontalement en ajoutant des instances et en y plaçant de nouveaux locataires.
Cette mécanique rejoint l'approche hybride évoquée en §20.4 : on peut combiner des instances mutualisées « schéma par locataire » pour la majorité des clients, et des silos dédiés (§20.4.1) pour les plus exigeants.
Le schéma par locataire convient lorsque :
- l'on sert un nombre modéré de locataires de taille moyenne, pour lesquels une instance dédiée par client serait un gaspillage ;
- l'on souhaite une isolation logique solide et des opérations par locataire (sauvegarde, restauration, suppression ciblées) sans le coût du silo ;
- une personnalisation occasionnelle par locataire reste souhaitable ;
- la simplicité d'évitement du filtrage applicatif (par rapport au schéma partagé) est appréciée.
À l'inverse, ce modèle atteint ses limites face à un très grand nombre de petits locataires, où l'explosion du nombre de tables le rend inefficient : on lui préférera alors le schéma partagé (§20.4.3), qui mutualise jusqu'aux tables. C'est précisément ce modèle de densité maximale qu'aborde la section suivante.
⬅️ Section précédente : 20.4.1 Database per tenant
➡️ Section suivante : 20.4.3 Shared schema avec discriminateur
⬆️ Retour au sommaire