Sollte ein Multi-Tenant-System mit SQL Server 2016, Shard oder Tenant-Isolation über eine separate Datenbank pro Tenant verfügen?

12

In Anbetracht des Anwendungsfalls:

  • Die Daten eines Mieters sollten nicht miteinander verhandelt werden. Ein Mieter benötigt keine Daten eines anderen Mieters.
  • Jeder Mieter verfügt möglicherweise über ein großes historisches Datenvolumen.
  • SQL Server wird in einer AWS EC2-Instanz gehostet.
  • Jeder Mieter ist geografisch weit entfernt.
  • Es besteht die Absicht, Visualisierungstools von Drittanbietern wie PowerBI Embedded zu verwenden
  • Das Datenvolumen wird voraussichtlich im Laufe der Zeit zunehmen
  • Die Kosten des Systems sind begrenzt.
  • Die Lösung muss ohne einen 24/7-Produktions-DBA wartbar sein
  • Die Lösung sollte horizontal skalierbar sein.
  • Die Gesamtzahl der Mieter beträgt weniger als 50

Was wäre eine empfohlene Architektur? Gibt es Referenzimplementierungen für diesen Anwendungsfall? Ich glaube, dass viele Menschen dieses Problem bei der Entwicklung von Unternehmenssoftware bereits hatten.

Ich denke, dies ist eine andere Situation als der Umgang mit einer wachsenden Anzahl von Mandanten in der Datenbankarchitektur mit mehreren Mandanten . Der in dieser Frage erwähnte Anwendungsfall befasst sich mit einer höheren Anzahl von Mietern, was sich stark von der Anzahl von sehr wenigen (50) Großmietern unterscheidet. Die erwähnte Architektur könnte hier eine Lösung sein, worüber ich mehr wissen möchte.

DS
quelle

Antworten:

16

Das Problem beim Sharding ist, dass die Anwendung wissen muss, welche Shards abgefragt werden sollen. Im Allgemeinen geschieht dies durch Splittern auf so etwas wie einem Client. Ich werde einen meiner alten Blog-Posts anpassen , um ihn als meine Antwort zu verwenden.

Wenn Sie eine Anwendung für viele Clients erstellen, gibt es zwei gängige Methoden zum Entwerfen der Datenbank (en):

  • Option A: Legen Sie alle Clients in derselben Datenbank ab
  • Option 2: Erstellen Sie eine Datenbank pro Client

Alle Clients in dieselbe Datenbank stellen

Es ist ganz einfach: Fügen Sie einfach eine Client-Tabelle am oberen Rand des Schemas hinzu, fügen Sie eine ClientUsers-Tabelle hinzu, um sicherzustellen, dass die Benutzer nur ihre eigenen Daten sehen.

Vorteile dieses Ansatzes:

Einfacheres Schema-Management. Wenn Entwickler eine neue Version der Anwendung bereitstellen, müssen sie nur Schemaänderungen in einer Datenbank vornehmen. Es besteht keine Gefahr, dass verschiedene Kunden nicht synchronisiert sind oder die falsche Version verwenden.

Einfachere Leistungsoptimierung. Wir können die Indexnutzung und Statistiken an nur einer Stelle überprüfen, Verbesserungen einfach implementieren und die Auswirkungen auf alle unsere Kunden sofort sehen. Bei Hunderten oder Tausenden von Datenbanken kann es schwierig sein, selbst kleinste Änderungen zu koordinieren. Wir können den Inhalt des Prozedurcaches überprüfen und feststellen, welche Abfragen oder gespeicherten Prozeduren in der gesamten Anwendung am intensivsten sind. Wenn wir jedoch separate Datenbanken pro Client verwenden, kann es zu einer härteren Zeit für die Aggregation der Abfragen in verschiedenen Ausführungsplänen kommen.

Einfacheres Erstellen einer externen API. Wenn wir Außenstehenden Zugriff auf unsere gesamte Datenbank gewähren müssen, um Produkte zu erstellen, können wir dies einfacher tun, wenn sich alle Daten in einer einzigen Datenbank befinden. Wenn die API Daten aus mehreren Datenbanken auf mehreren Servern gruppieren muss, verlängert sich die Entwicklungs- und Testzeit. (Auf der anderen Seite deutet diese Sache mit mehreren Servern auf eine Einschränkung für das Szenario mit einer Datenbank für alle Regeln hin: Eine Datenbank bedeutet normalerweise, dass sich unsere gesamte Auslastung nur auf einen Datenbankserver auswirkt.) In Ihrem Fall Mit PowerBI wird die Verwaltung von Verbindungen erheblich vereinfacht, wenn alle Benutzer in einer Datenbank sind.

Einfachere Hochverfügbarkeit und Notfallwiederherstellung. Es ist wirklich sehr einfach, die Datenbankspiegelung, den Protokollversand, die Replikation und das Clustering zu verwalten, wenn wir uns nur um eine einzige Datenbank kümmern müssen. Wir können schnell eine verdammte Infrastruktur aufbauen.

Platzieren jedes Clients in einer eigenen Datenbank oder einem eigenen Shard

Sie benötigen noch eine Client-Auflistung, die jetzt jedoch zu einem Verzeichnis wird. Sie verfolgen für jeden Client auch den Shard, in dem er sich befindet. Beim Start fragt Ihre App diese Tabelle ab und speichert sie im RAM zwischen. Wenn Daten für einen Client benötigt werden, wird eine direkte Verbindung zu diesem Shard (Datenbank und Server) hergestellt.

Vorteile dieses Ansatzes:

Einfachere Wiederherstellung auf einem einzelnen Client. Kunden sind unzuverlässige Fleischsäcke. (Außer meiner - sie sind verlässliche Fleischsäcke.) Sie haben alle möglichen Momente, in denen sie all ihre Daten zu einem bestimmten Zeitpunkt zurückholen möchten, und das ist ein großer Schmerz im Hintergrund, wenn sich ihre Daten mit denen vermischen andere Kundendaten in den gleichen Tabellen. Wiederherstellungen in einem Szenario mit einer einzelnen Client-Datenbank sind denkbar einfach: Stellen Sie einfach die Client-Datenbank wieder her. Sonst ist niemand betroffen.

Einfacherer Datenexport. Kunden lieben es, ihre Daten in den Griff zu bekommen. Sie möchten die Gewissheit haben, dass sie ihre Daten jederzeit abrufen können, um das gefürchtete Szenario der Lieferantenbindung zu vermeiden, und sie möchten ihre eigenen Berichte erstellen. Wenn die Daten jedes Kunden in seiner eigenen Datenbank isoliert sind, können wir ihnen einfach eine Kopie ihrer eigenen Datenbanksicherung geben. Wir müssen keine Datenexport-APIs erstellen.

Einfachere Skalierbarkeit für mehrere Server. Wenn unsere Anwendung mehr Leistung benötigt, als wir von einem einzelnen Server erhalten können, können wir die Datenbanken auf mehrere Server aufteilen. Wir können die Last auch geografisch verteilen, um Server in Asien oder Europa näher am Kunden zu platzieren.

Einfachere Leistungsoptimierung pro Client. Wenn einige Clients unterschiedliche Funktionen oder Berichte verwenden, können wir einen speziellen Satz von Indizes oder indizierten Ansichten nur für diese Clients erstellen, ohne die Datengröße aller zu erhöhen. Zugegeben, hier besteht ein gewisses Risiko: Indem wir Schemaunterschiede zwischen Clients zulassen, haben wir gerade unsere Code-Bereitstellungen etwas riskanter und unser Leistungsmanagement schwieriger gemacht.

Einfacheres Sicherheitsmanagement. Solange wir die Sicherheit mit einem Benutzer pro Datenbank ordnungsgemäß gesperrt haben, müssen wir uns keine Sorgen machen, dass Client X auf die Daten von Client Y zugreift. Wenn wir jedoch nur ein einziges Login für alle Benutzer verwenden, haben wir dieses Problem nicht wirklich gelöst.

Einfachere Wartungsfenster. In einer globalen Umgebung, in der Kunden auf der ganzen Welt verteilt sind, ist es einfacher, Kunden zur Wartung offline zu schalten, wenn dies in Gruppen oder Zonen möglich ist.

Welches ist das Richtige für Sie?

Es gibt keine richtige Wahl: Sie müssen die Stärken und Schwächen Ihres eigenen Unternehmens kennen. Nehmen wir zwei meiner Kunden als Beispiele.

Unternehmen A zeichnet sich durch Hardware-Leistungsoptimierung aus. Sie sind wirklich sehr, sehr gut darin, der Hardware das allerletzte Maß an Leistung zu entziehen, und es macht ihnen nichts aus, ihre SQL Server-Hardware in einem Zyklus von 12 bis 18 Monaten auszutauschen. (Sie aktualisieren die Webserver alle 4 bis 6 Monate!) Ihre Achillesferse stellt extreme Compliance- und Sicherheitsanforderungen. Sie haben einen unglaublichen Prüfbedarf und es ist für sie nur einfacher, kugelsichere Kontrollen auf einem einzigen Server und einer einzigen Datenbank zu implementieren, als diese Anforderungen auf Tausenden von Datenbanken auf Dutzenden von Servern zu verwalten. Sie wählten eine Datenbank, einen Server und viele Clients.

Unternehmen 2 zeichnet sich durch Entwicklungspraktiken aus. Das Verwalten von Schemaänderungen und Code-Bereitstellungen in Tausenden von Datenbanken ist für sie kein Problem. Sie haben Kunden auf der ganzen Welt und wickeln für diese Kunden rund um die Uhr Kreditkartentransaktionen ab. Sie müssen in der Lage sein, die Last geografisch zu verteilen, und sie möchten Server nicht alle 12 bis 18 Monate auf der ganzen Welt austauschen. Sie wählten eine Datenbank für jeden Client und es lohnt sich, wenn sie damit beginnen, SQL Server für ihre Offshore-Clients in Asien und Europa zu installieren.

Brent Ozar
quelle
"In Ihrem Fall wird die Verwaltung von Verbindungen mit PowerBI viel einfacher, wenn alle in einer Datenbank sind." Gerade jetzt Embedded PowerBI nicht auf Zeilenebene Sicherheit haben und damit jeder Mieter in einer Datenbank, die verursacht einige Zweifel an diesen Anwendungsfall finden Sie unter : community.powerbi.com/t5/Developer/... , im Lichte dieser Informationen könnten Sie bitte rephrase dies oder eine alternative vorschlagen oder mein verständnis korrigieren?
DS
Außerdem können Sie mit "Jeden Client in eine eigene Datenbank oder einen eigenen Shard stellen" den Unterschied zwischen diesen beiden Vorschlägen erläutern
DS
Ich sage nur, dass die Bereitstellung in mehr als einer Datenbank nicht so schlimm ist, wie Sie es klingen lassen. Im Jahr 2017 haben wir viele Optionen, die es sehr einfach machen, Änderungen an 1, 5 oder 900 Datenbanken bereitzustellen. Und wenn Sie Ausnahmen für bestimmte Kunden haben, können diese in der Regel so in diese Datenbanken eingefügt werden, dass sie den allgemeinen Code nicht beeinträchtigen.
Aaron Bertrand
5

Eine weitere Überlegung habe ich in anderen Antworten noch nicht gesehen.

Ein Design, das viele Mandanten in einer einzigen Datenbank ermöglicht, gibt später Flexibilität. Wenn das Laden / Skalieren / Sicherheits- / Geostandort-Erfordernis später vorschlägt, dass ein Mandant über eine separate Datenbank verfügt, kann diese erstellt werden, indem die aktuelle Datenbank auf der neuen Instanz wiederhergestellt wird. Die Daten der anderen Mieter sind weiterhin durch die vorhandenen Mechanismen geschützt. Die inzwischen veralteten Daten können nach Bedarf schrittweise aus alten und neuen Datenbanken entfernt werden.

Das Gegenteil ist nicht wahr. Die Konsolidierung vieler Datenbanken mit einem Mandanten erfordert erheblich mehr Arbeit.

Michael Green
quelle
4

Eine Methode, die Multi-Tenant-Modelle erheblich vereinfacht, obwohl sie die Normalisierung aufheben *, besteht darin, in jede Tabelle eine Spalte für den Tenant aufzunehmen. Sie könnten es TenantID nennen. Auf diese Weise kann jede Abfrage, die für die Datenbank ausgeführt wird, nach TenantID für jede Tabelle gefiltert werden. Mithilfe der Datenbankpartitionierung können Sie die Daten für jeden Tenant isolieren und Abfragen beschleunigen, indem Partitionen ausgerichtet werden. Es ist viel einfacher, alle Mandanten auf diese Weise in einer Datenbank zu haben.

* Es bricht nicht immer die Normalisierung, aber es kann. Zum Beispiel, wenn Sie eine Personund eine PersonAddressTabelle haben. Die PersonTabelle hat TenantID, PersonIDals Primärschlüssel. Die PersonAddressTabelle hat TenantID, PersonID, AddressTypeIDals Primärschlüssel, was ich vorschlage.

Normalerweise PersonIDwürde gerade ausreichen, weil Sie das zurück zum PersonTisch verbinden könnten, um das zu finden Tenant. Ich schlage vor, dass Sie TenantIDzu jedem nachfolgenden Tisch weitermachen, selbst wenn ein dünnerer Schlüssel funktionieren würde.

Nach meinem Verständnis galt das Übertragen von Informationen in eine Tabelle, die aus anderen Daten abgeleitet werden konnten, als Verstoß gegen die Normalisierung. Aber vielleicht ist die Verwendung dünner Schlüssel nur eine bewährte Methode.

Matthew Sontum
quelle
Vielen Dank, ich bin mit dem Vorschlag einverstanden und möchte zusätzlich erwähnen, dass dieses Feld TenantID ein Integer-Typ und keine GUID sein muss.
DS
3
Aber selbst wenn Sie die TenantID in untergeordnete Tabellen übernehmen, was Sie nicht tun müssen, bedeutet ein breiterer Schlüssel nicht, dass die Normalisierung "kaputt" ist. Genauso wie die Auswahl einer GUID über IDENTITY (einem breiteren Schlüssel) die Normalisierung nicht unterbricht, und auch die Auswahl eines breiteren natürlichen Schlüssels, anstatt überhaupt Ersatzschlüssel zu verwenden.
Aaron Bertrand