architecture optimale pour une application multitenant sur Django




multi-tenant (3)

Je me suis penchée sur la manière correcte / optimale de créer une application multitenancy basée sur Django.

Quelques explications:

  • L'application peut être utilisée par plusieurs locataires (locataire1, locataire2, ...).

  • Toutes les données individuelles du locataire doivent être sécurisées contre l'accès des autres locataires (et de leurs utilisateurs).

  • Les locataires peuvent éventuellement créer des champs personnalisés supplémentaires pour les objets d'application.

  • Bien entendu, le matériel sous-jacent limite le nombre de locataires sur un "système".

1) Séparer chaque locataire par ex. Sous-domaine et utiliser des bases de données spécifiques au locataire dans la couche sous-jacente

2) Utilisation d'un identifiant de client dans le modèle pour séparer les données de client dans la base de données

Je pense aux processus de déploiement, aux performances des parties du système (serveur (s) Web, serveur (s) de base de données, nœud (s) de travail, ...)

Quelle serait la meilleure configuration? Où sont les avantages et les inconvénients?

Qu'est-ce que tu penses?




Nous avons construit une plate- platform multitenancy en utilisant l'architecture suivante. J'espère que vous pouvez trouver des conseils utiles.

  • Chaque locataire obtient un sous-domaine (t1.example.com)
  • En utilisant la réécriture d'url, les requêtes pour l'application Django sont réécrites pour quelque chose comme example.com/t1
  • Toutes les définitions d'URL sont préfixées par quelque chose comme (r'^(?P<tenant_id>[\w\-]+)
  • Un middleware traite et consomme le tenant_id et l'ajoute à la requête (par exemple request.tenant = 't1')
  • Le locataire actuel est désormais disponible dans chaque vue sans spécifier l'argument tenant_id à chaque vue.
  • Dans certains cas, la demande n'est pas disponible. J'ai résolu ce problème en liant le tenant_id au thread en cours (similaire à la langue en cours en utilisant threading.local )
  • Créer des décorateurs (par exemple un login_required ), des middlewares ou des usines pour protéger les vues et sélectionner les bons modèles
  • En ce qui concerne les bases de données, j'ai utilisé deux scénarios différents:
    • Configurez plusieurs bases de données et configurez un routing fonction du client actuel. Je l'ai utilisé en premier mais j'ai changé de base de données après environ un an. Les raisons étaient les suivantes:
      • Nous n'avons pas eu besoin d'une solution hautement sécurisée pour séparer les données
      • Les différents locataires utilisaient presque tous les mêmes modèles
      • Nous avons dû gérer beaucoup de bases de données (et ne pas avoir mis en place un processus de mise à jour / migration facile)
    • Utilisez une base de données avec des tables de mappage simples pour les utilisateurs et différents modèles. Pour ajouter des champs de modèle supplémentaires et spécifiques au locataire, nous utilisons l' héritage de modèle .

En ce qui concerne l'environnement, nous utilisons la configuration suivante:

De mon point de vue, cette configuration a les avantages et inconvénients suivants:

Pro:

  • Une instance d'application connaissant le locataire actuel
  • La plupart des parties du projet ne doivent pas se soucier des problèmes spécifiques des locataires
  • Solution facile pour partager des entités entre tous les locataires (par exemple, des messages)

Contra:

  • Une base de données assez grande
  • Quelques tableaux très similaires en raison de l'héritage du modèle
  • Non sécurisé sur la couche de base de données

Bien entendu, la meilleure architecture dépend fortement de vos besoins en termes de nombre de clients, de delta de vos modèles, d'exigences de sécurité, etc.

Mise à jour : Comme nous avons examiné notre architecture, je suggère de ne pas réécrire l'URL comme indiqué au point 2-3. Je pense que la meilleure solution consiste à placer le tenant_id tant qu'en-tête de demande et à extraire (point 4) le tenant_id de la requête avec quelque chose comme request.META.get('TENANT_ID', None) . De cette façon, vous obtenez des URL neutres et il est beaucoup plus facile d'utiliser les fonctions intégrées de Django (par exemple {% url ...%} ou reverse() ) ou des applications externes.







multi-tenant