Gestion d'un nombre croissant de locataires dans une architecture de base de données multi-locataires

26

La gestion d'un nombre modeste de clients (locataires) sur un serveur commun avec des bases de données distinctes pour chaque instance de l'application de chaque locataire est relativement simple et constitue normalement la bonne façon de procéder. Actuellement, je regarde l'architecture d'une application où chaque locataire a sa propre instance de base de données.

Cependant, le problème est que cette application aura un grand nombre de locataires (5 000 à 10 000) avec un nombre important d'utilisateurs, peut-être 2 000 pour un seul locataire. Nous devrons soutenir la croissance du système par plusieurs locataires chaque semaine.

De plus, tous les locataires et leurs utilisateurs se verront présenter un processus de connexion commun (c'est-à-dire que chaque locataire ne peut pas avoir sa propre URL). Pour ce faire, j'ai besoin d'un processus de connexion centralisé et d'un moyen d'ajouter dynamiquement des bases de données au système et d'enregistrer les utilisateurs.

  • Comment le processus d'enregistrement et de création de base de données pourrait-il être automatisé de manière robuste?

  • Le processus de création et d'enregistrement des bases de données des locataires sur le système est-il susceptible de provoquer des problèmes de performances ou de verrouillage. Si vous pensez que cela pourrait être un problème, quelqu'un peut-il suggérer des moyens de l'atténuer?

  • Comment puis-je gérer l'authentification centrale de manière à ce que les informations d'identification de l'utilisateur soient associées à la base de données d'un locataire particulier, mais l'utilisateur peut se connecter via une page commune (c'est-à-dire tout au long de la même URL de connexion, mais leur application domestique se trouvera sur la base de données d'un locataire spécifique ). Les locataires devront être en mesure de maintenir leurs propres connexions et autorisations, mais un système de connexion central doit en être conscient. Quelqu'un peut-il suggérer un moyen de procéder?

  • Si je dois évoluer en ajoutant plusieurs serveurs de base de données, quelqu'un peut-il suggérer les problèmes que je pourrais avoir à gérer dans la gestion des identités des utilisateurs sur les serveurs (usurpation d'identité, etc.) et un moyen d'atténuer ces problèmes?

coddey
la source
1
Je n'ai pas eu à faire face à une situation comme celle-ci, mais mon intuition serait de gérer le déploiement des locataires en préconfigurant les serveurs avec autant de bases de données de locataires que vous pensez qu'ils peuvent gérer, puis d'affecter les bases de données de locataires prédéfinies en tant que nouveaux locataires s'inscrire. De cette façon, vous n'avez pas à vous soucier de la contention des ressources lors du déploiement des bases de données locataires au moins.
Joel Brown
1
Êtes-vous sûr de trouver près de 5 000 à 10 000 locataires? Et que tous vos locataires seront dans la plage des 2 000 utilisateurs? Dans mon système, je pense que le plus grand nombre d'utilisateurs de notre application pour un seul locataire était d'environ 100. Et parmi ceux-ci, seulement 20 environ étaient constamment actifs. Puis-je demander quelle est l'industrie / application?
Aaron Bertrand
@AaronBertrand C'est un système de gestion de l'apprentissage où les services seront partiellement gratuits et partiellement payés.
coddey

Réponses:

25

À l'extrémité inférieure (500 locataires / 10000 utilisateurs), c'est comme ça que je l'ai fait. Premièrement, vous avez une base de données «de contrôle» qui est globale, centrale et contient toutes les informations sur les locataires et les utilisateurs (je ne pense vraiment pas que vous souhaitiez les gérer en tant que connexions d'authentification SQL). Imaginez donc une base de données appelée "Control" avec les tableaux suivants:

CREATE TABLE dbo.Instances
(
  InstanceID INT PRIMARY KEY,
  Connection VARCHAR(255)
  --, ...
);

INSERT dbo.Instances SELECT 1, 'PROD1\Instance1';
INSERT dbo.Instances SELECT 1, 'PROD2\Instance1';
-- ...

CREATE TABLE dbo.Tenants
(
  TenantID INT PRIMARY KEY,
  Name NVARCHAR(255) NOT NULL UNIQUE,
  InstanceID INT -- Foreign key tells which instance this tenant's DB is on
  --, ...
);

INSERT dbo.Tenants SELECT 1, 'MyTenant', 1;
-- ...

CREATE TABLE dbo.Users
(
  UserID INT PRIMARY KEY,
  Username VARCHAR(320) NOT NULL UNIQUE,
  PasswordHash VARBINARY(64), -- because you never store plain text, right?
  TenantID INT -- foreign key
  --, ...
);

INSERT dbo.Users SELECT 1, '[email protected]', 0x43..., 1;

Dans notre cas, lorsque nous ajoutions un nouveau locataire, nous construisions la base de données dynamiquement, mais pas lorsque l'utilisateur administrateur cliquait sur OK dans l'interface utilisateur ... nous avions un travail en arrière-plan qui retirait les nouvelles bases de données d'une file d'attente toutes les 5 minutes, définissait le modèle sur single_user , puis créé chaque nouvelle base de données en série. Nous l'avons fait pour (a) empêcher l'utilisateur administrateur d'attendre la création de la base de données et (b) pour éviter que deux utilisateurs administrateur tentent de créer une base de données en même temps ou se voient refuser la possibilité de verrouiller le modèle (requis lors de la création d'une nouvelle base de données) ).

Les bases de données ont été créées avec le schéma de noms Tenant000000xxoù elles étaient xxreprésentées Tenants.TenantID. Cela a rendu les travaux d'entretien assez facile, au lieu d'avoir toutes sortes de bases de données nommées BurgerKing, McDonalds, KFCetc. Non que nous étions dans la restauration rapide, juste en utilisant comme exemple.

La raison pour laquelle nous n'avons pas pré-alloué des milliers de bases de données, comme le suggère le commentaire, est que nos utilisateurs administrateurs avaient généralement une idée de la taille du locataire, de leur priorité, etc. Ils avaient donc des choix de base dans l'interface utilisateur qui dicterait leur taille initiale et leurs paramètres de croissance automatique, vers quel sous-système de disque leurs fichiers de données / journaux iraient, leurs paramètres de récupération, le calendrier de sauvegarde sur lequel s'articuler, et même une idée de l'instance vers laquelle déployer la base de données afin d'équilibrer au mieux l'utilisation ( bien que nos administrateurs puissent passer outre). Une fois la base de données créée, la table des locataires a été mise à jour avec l'instance choisie, un utilisateur administrateur a été créé pour le locataire et nos administrateurs ont reçu par e-mail les informations d'identification à transmettre au nouveau locataire.

Si vous utilisez un seul point d'entrée, il n'est pas possible d'autoriser plusieurs locataires à avoir des utilisateurs avec le même nom d'utilisateur. Nous avons choisi d'utiliser l'adresse e-mail, ce qui - si tous les utilisateurs travaillent pour l'entreprise et utilisent leur adresse e-mail d'entreprise - devrait convenir. Bien que notre solution soit finalement devenue plus complexe pour deux raisons:

  1. Nous avions des consultants qui travaillaient pour plus d'un de nos clients et nous avions besoin d'accéder à plusieurs
  2. Nous avions des locataires qui eux-mêmes étaient en fait composés de plusieurs locataires

Nous nous sommes donc retrouvés avec une TenantUserstable qui permettait à un utilisateur d'être associé à plusieurs locataires.

Initialement, lorsqu'un utilisateur se connecte, l'application ne connaît que la chaîne de connexion pour la base de données de contrôle. Lorsqu'une connexion réussit, il peut alors créer une chaîne de connexion basée sur les informations trouvées. Par exemple

SELECT i.Connection
  FROM dbo.Instances AS i
  INNER JOIN dbo.Tenants AS t
  ON i.InstanceID = t.InstanceID
  INNER JOIN dbo.TenantUsers AS u
  ON i.TenantID = u.TenantID
  WHERE u.UserID = @UserID;

Maintenant, l'application peut se connecter à la base de données de l'utilisateur (chaque utilisateur a un locataire par défaut ) ou l'utilisateur peut sélectionner l'un des locataires auxquels il peut accéder. L'application récupère alors simplement la nouvelle chaîne de connexion et redirige vers la page d'accueil de ce locataire.

Si vous entrez dans cet espace utilisateur de 10 mm que vous proposez, vous en aurez certainement besoin pour être mieux équilibré. Vous souhaiterez peut-être fédérer l'application afin qu'ils aient différents points d'entrée se connectant à différentes bases de données de contrôle. Si vous donnez à chaque locataire un sous-domaine (par exemple, TenantName.YourApplicationDomain.com), vous pouvez le faire en arrière-plan avec DNS / routage sans les interrompre lorsque vous devez évoluer.

Il y a beaucoup plus à cela - comme @Darin, je ne fais qu'effleurer la surface ici. Faites-moi savoir si vous avez besoin d'une consultation non gratuite. :-)

Aaron Bertrand
la source
Merci d'avoir partagé votre expérience, en effet, elle m'a éclairé, j'en cherche encore plus. Mais vous avez déjà écrit Non-free. :(
coddey
1
Mon point était que je n'ai que si peu de temps à consacrer à des conseils gratuits. :-)
Aaron Bertrand
+1 - à peu près exactement la même approche que j'ai utilisée auparavant. ~ Le même nombre de locataires a également très bien fonctionné.
AdaTheDev
Comment gérer la relation entre la base de données principale et la base de données des locataires? (sans utilisation de déclencheurs, etc.)
Jitendra Pancholi
@jitendra pas vraiment beaucoup d'options - combien de données avez-vous vraiment dans une base de données de locataires qui doivent se rapporter aux données de la base de données master? Je ne suis pas sûr non plus de comprendre la peur populaire des déclencheurs - un déclencheur correctement écrit n'a rien à craindre ...
Aaron Bertrand
10

Vous avez vous-même un projet assez intéressant. Je n'ai jamais vu directement quelqu'un essayer d'implémenter quelque chose d'aussi gros, du moins sur SQL Server. Plus je lis votre message, plus je pose de questions ...

Dans le pire des cas, en ce qui concerne l'infrastructure (qui est en fait le meilleur des cas, en termes commerciaux), vous avez besoin de 10 000 bases de données pour 2 000 utilisateurs. Cela représente 20 000 000 d'utilisateurs. Vous n'allez pas réussir à gérer 20 millions de connexions SQL Server. OMI. Juste le nombre d'entre eux, traitant de les déplacer d'un serveur à un autre, de surveiller les collisions d'ID et les ID incompatibles, et je ne sais pas comment SQL Server se comporterait avec 20 millions de lignes dans sys.server_principals. De plus, votre application Web voudra probablement se connecter en tant qu'utilisateur unique ou très faible. IIS ne peut pas regrouper les connexions à moins que leurs chaînes DSN soient identiques. L'un des attributs d'une chaîne DSN est le nom d'utilisateur. Différents utilisateurs signifie pas de mise en commun.

Vous devrez rouler votre propre schéma d'identification d'utilisateur. Il devra être en mesure de déterminer à quel locataire appartient un utilisateur, puis votre code Web devra sélectionner la base de données appropriée. Ces métadonnées utilisateur sont essentielles, elles devront être stockées quelque part, elles devront être regroupées ou mises en miroir, elles devront être rapides et elles devront être bien protégées (du point de vue de la sécurité. IOW, crypter.). En supposant que SQL est même une bonne idée ici, je garderais cette base de données à l'écart des instances des serveurs. Cela aide d'un point de vue de la sécurité et d'un point de vue de la charge, bien que je suppose qu'une fois qu'un utilisateur est validé et que l'application Web est dirigée vers la base de données correcte sur une autre instance, il n'y aura plus d'interrogation de ces métadonnées utilisateur liées à cela utilisateur.

Question rapide: deux utilisateurs différents, appartenant à deux locataires différents, devraient-ils avoir le même nom d'utilisateur?

Une autre question rapide: si je vous dis que je travaille pour FuBar, Inc., comment savez-vous cela? Est-ce que FuBar va vous donner une liste d'utilisateurs et vous leur rendrez une liste de noms d'utilisateurs, ou vont-ils s'auto-approvisionner?

Vous allez devoir passer à plusieurs instances. Si même une fraction de ces utilisateurs décident de lancer l'application en même temps, une seule instance fondra. Il n'aura pas suffisamment de threads de travail pour exécuter toutes ces demandes à la fois. Si seulement 1000 utilisateurs atteignent votre instance en même temps, il n'y aura probablement plus de threads de travail et la demande commencera à s'empiler et à attendre. J'ai vu cela arriver; le symptôme immédiat est que les nouvelles connexions ne pourront pas se connecter à l'instance car il n'y a pas de threads de travail disponibles pour les entretenir. S'il s'agit d'un comportement de très courte durée, votre application peut survivre. Sinon, ou si votre application est difficile, les utilisateurs obtiendront des erreurs.

Même si vous n'avez pas beaucoup de locataires à démarrer, vous devriez commencer à penser à l'avenir et à l'automatisation car lorsque vous voyez que votre serveur est enlisé et qu'il y a 10 nouveaux locataires à mettre en ligne, il est beaucoup trop tard et votre service (et vos clients et vos futurs ex-clients) souffriront jusqu'à ce que vous écriviez votre moyen de sortir du problème.

Vous allez avoir besoin d'un moyen de déplacer les bases de données, des serveurs surchargés aux serveurs légèrement chargés (ou nouveaux). Que vous puissiez ou non obtenir une fenêtre d'indisponibilité dépendra de votre SLA.

Fournissez-vous une application spécifique, comme SalesForce, ou ces bases de données sont-elles simplement des conteneurs pour tout ce que vos locataires veulent y mettre?

Quelle est la taille des bases de données? S'ils ne sont pas très gros, vous pouvez simplement restaurer à partir d'un fichier de sauvegarde qui fournit un modèle. (Ce n'est pas très différent de ce que fait la base de données de modèles, mais je n'ai vu personne vraiment utiliser le modèle dans le bon sens depuis mes jours avec SQL 6.5.) Une fois que le modèle a été restauré avec le nouveau nom de la base de données, vous pouvez puis personnalisez la nouvelle base de données selon les besoins d'un locataire particulier. Vous ne pouvez pas faire la personnalisation avant d'avoir le locataire, évidemment. Si la base de données est volumineuse, vous pouvez suivre la même procédure de base, sauf que vous effectuez la restauration à l'avance, avant qu'un nouveau locataire ait besoin de l'espace. Vous pouvez conserver quelques-unes de ces bases de données, peut-être une par instance. Si vous en gardez trop, cela vous obligera peut-être à acheter plus de matériel et / ou de stockage que vous n'en avez besoin,

S'il s'agit de votre propre application, comment allez-vous gérer les mises à jour des schémas? Comment allez-vous conserver les versions de la base de données directement avec les versions du code, si vous utilisez une seule URL qui accède à votre application Web?

Comment détecter et détruire les bases de données qui ne sont plus utilisées? Attendez-vous que votre groupe A / R dise que quelqu'un n'a pas payé sa facture depuis trois mois?

Si les locataires gèrent des autorisations, cela implique qu'ils ont une certaine compréhension du fonctionnement interne de l'application ou que votre application a une structure de rôle très simple. En utilisant un exemple comme Blogger, les utilisateurs peuvent (lire les articles), (lire les articles et faire des commentaires), (... et créer des articles), (... et modifier les articles des autres), (... et peuvent réinitialiser mots de passe des autres utilisateurs), ou (... et autre). Avoir un rôle pour chacun de ces différents ensembles de droits et affecter un utilisateur à un rôle ou à un autre ne devrait pas être trop difficile, mais vous ne voulez pas que votre application exécute des instructions 'GRANT'. Méfiez-vous des rôles qui ont une hiérarchie et dépendent de l'héritage, cela peut être déroutant. Si vous faites la promotion ou la rétrogradation d'un utilisateur, je dirais de le retirer de tous les rôles associés, puis de le rajouter au seul rôle dont il a besoin. Oh,

Je pense que je n'ai fait qu'effleurer la surface ici, et ce post est déjà trop long. Ce dont vous avez vraiment besoin, c'est d'un livre, ou du moins d'un livre blanc de quelqu'un qui l'a fait. La plupart de ces gars ne parleront pas s'ils considèrent cela comme un avantage concurrentiel.

détroit de darin
la source
Merci pour les commentaires, le projet est intéressant. En raison de la limitation des mots, je maintiens le commentaire très précis. Il s'agit d'un système de gestion de l'apprentissage où chaque locataire aura environ 120 à 150 tables. Aucun utilisateur n'aura le même nom d'utilisateur quel que soit le locataire. Pour réduire encore la complexité, le mappage CNAME DNS sera utilisé par exemple tenant1.abc.com. Maintenant, le point d'ébullition est - le concevoir de manière correcte afin qu'il réponde à toutes les suggestions que vous avez partagées et je m'inquiète. Obtenir un livre blanc sera louable mais ce n'est pas facile, peut-être. Vous cherchez plus d'entrée si vous le pouvez. !!!!
coddey