Ein kleiner Hintergrund
Ich verwende das Apartment-Juwel seit Jahren, um eine Mandantenfähigkeits-App auszuführen. Vor kurzem ist die Notwendigkeit angekommen, die Datenbank auf separate Hosts zu skalieren. Der Datenbankserver kann einfach nicht mehr mithalten (sowohl Lese- als auch Schreibvorgänge werden zu viel) - und ja, ich habe die Hardware maximal skaliert (dediziert) Hardware, 64 Kerne, 12 Nvm-e-Laufwerke in RAID 10, 384 GB RAM usw.).
Ich habe überlegt, dies pro Mandant (1 Mandant = 1 Datenbankverbindungskonfiguration / number-of-tenants
-pool) durchzuführen , da dies eine "einfache" und effiziente Möglichkeit wäre, bis zu- mal mehr Kapazität zu erreichen, ohne viele Änderungen am Anwendungscode vorzunehmen.
Jetzt laufe ich Schienen mit 4,2 atm und rüste bald auf 5,2 auf. Ich kann sehen, dass Rails 6 die Unterstützung für Verbindungsdefinitionen pro Modell hinzufügt, aber das ist nicht wirklich das, was ich brauche, da ich für jeden meiner 20 Mandanten ein vollständig gespiegeltes Datenbankschema habe. Normalerweise wechsle ich "Datenbank" pro Anfrage (in Middleware) oder pro Hintergrundjob (Sidekiq Middleware). Dies ist jedoch derzeit trivial und wird vom Apartment-Juwel behandelt, da es nur die search_path
in Postgresql festlegt und die tatsächliche Verbindung nicht wirklich ändert. Wenn ich zu einer Mandanten-Hosting-Strategie wechsle, muss ich die gesamte Verbindung pro Anfrage wechseln.
Fragen:
- Ich verstehe, dass ich einen
ActiveRecord::Base.establish_connection(config)
Job pro Anfrage / Hintergrund ausführen könnte - aber wie ich auch verstehe, löst dies einen völlig neuen Handshake für die Datenbankverbindung und einen neuen Datenbankpool aus, der in Rails erzeugt wird - richtig? Ich denke, das wäre ein Leistungsselbstmord, um diese Art von Overhead bei jeder einzelnen Anfrage an meine Bewerbung zu verursachen. - Ich frage mich daher, ob jemand die Option mit Schienen sehen kann, z. B. mehrere (insgesamt 20) Datenbankverbindungen / -pools von Anfang an (z. B. beim Booten der Anwendung) vorab einzurichten und dann einfach pro Anforderung zwischen diesen Pools zu wechseln. Damit sind die DB-Verbindungen bereits hergestellt und einsatzbereit.
- Ist das alles nur eine schlechte Idee, und sollte ich stattdessen nach einem anderen Ansatz suchen? ZB 1 App-Instanz = eine bestimmte Verbindung zu einem bestimmten Mandanten. Oder etwas anderes.
quelle
master
Zweig benötigen . Wäre es eine Option, Rails Egde auszuführen oder diese Funktion auf Ihre aktuelle Rails-Version zurückzusetzen?ActiveRecord::Base.connected_to(shard: :shard_one) do ... end
bedeutet, dass der Pool (wieder) verwendet wird, anstatt jedes Mal eine ganz neue Verbindung herzustellen?Antworten:
Soweit ich weiß, gibt es 4 Muster für die Mandantenfähigkeits-App:
1. Spezielles Modell / mehrere Produktionsumgebungen
Jede Instanz oder Datenbankinstanz hostet vollständig eine andere Mandantenanwendung, und die Mandanten teilen nichts.
Dies ist 1 Instanz-App und 1 Datenbank für 1 Mandanten. Die Entwicklung wäre einfach, als würden Sie nur 1 Mieter bedienen. Aber es wird ein Albtraum für Devops, wenn Sie beispielsweise 100 Mieter haben.
2. Physische Trennung der Mieter
1 Instanz-App für alle Mandanten, aber 1 Datenbank für 1 Mandanten. Dies ist, wonach Sie suchen. Sie können
ActiveRecord::Base.establish_connection(config)
Edelsteine verwenden oder verwenden oder auf Rails 6 aktualisieren, wie andere vorschlagen. Siehe die Antwort für (2) unten.3. Isoliertes Schemamodell / Logische Segregationen
In einem isolierten Schema werden die Mandantentabellen oder Datenbankkomponenten unter einem logischen Schema oder Namensraum gruppiert und von anderen Mandantenschemata getrennt. Das Schema wird jedoch in derselben Datenbankinstanz gehostet.
1 Instanz-App und 1 Datenbank für alle Mieter, wie Sie es mit Apartment Gem tun.
4. Teilweise isolierte Komponente
In diesem Modell werden Komponenten mit gemeinsamen Funktionen von Mandanten gemeinsam genutzt, während Komponenten mit eindeutigen oder nicht verwandten Funktionen isoliert werden. Auf der Datenschicht werden allgemeine Daten wie Daten, die Mandanten identifizieren, gruppiert oder in einer einzigen Tabelle gespeichert, während mandantenspezifische Daten auf Tabellen- oder Instanzschicht isoliert werden.
Was (1)
ActiveRecord::Base.establish_connection(config)
betrifft , kein Handshake an db pro Anfrage, wenn Sie es richtig verwenden. Sie können hier überprüfen und den gesamten Kommentar hier lesen .Wie für (2), wenn Sie nicht verwenden möchten
establish_connection
, können Sie Edelstein- Multiversum (es funktioniert für Schienen 4.2) oder andere Edelsteine verwenden. Wie andere vorschlagen, können Sie auch auf Rails 6 aktualisieren.Bearbeiten: Multiverse Edelstein verwendet
establish_connection
. Es wird die angehängtdatabase.yml
und eine Basisklasse erstellt, sodass jede Unterklasse dieselbe Verbindung / denselben Pool verwendet. Grundsätzlich reduziert es unseren Aufwand zu verwendenestablish_connection
.Zu (3) lautet die Antwort:
Wenn Sie nicht so viele Mandanten haben und Ihre Anwendung ziemlich komplex ist, empfehlen wir Ihnen, das Muster "Dedicated Model" zu verwenden. Sie wählen also 1 App-Instanz = eine bestimmte Verbindung zu einem bestimmten Mandanten. Sie müssen Ihre Apps nicht komplexer gestalten, indem Sie mehrere Datenbankverbindungen hinzufügen.
Wenn Sie jedoch viele Mandanten haben, empfehlen wir Ihnen, die physische Trennung von Mandanten oder teilweise isolierten Komponenten abhängig von Ihrem Geschäftsprozess zu verwenden.
In beiden Fällen müssen Sie Ihre Anwendung aktualisieren / neu schreiben, um der neuen Architektur zu entsprechen.
quelle
establish_connection
in diesem Modellclass SecondTenantUser < ActiveRecord::Base; establish_connection(DB_SECOND_TENANT); end
Folgendes verwenden : und sagen, Sie haben 5 Modelle, erstellen Sie 5 Verbindungspools zum DB_SECOND_TENANT. Und jeder Pool wird gleich behandelt. Sie erstellen also keinen Pool pro Anforderung, sondern proestablish_connection
.Soweit ich weiß, sollte (2) mit manueller Verbindungsumschaltung in Rails 6 möglich sein.
quelle
Vor ein paar Tagen wurde Ruby on Rails ' Zweig auf GitHub um horizontales Sharding erweitert
master
. Derzeit ist diese Funktion nicht offiziell freigegeben. Abhängig von der Rails-Version Ihrer Anwendung möchten Sie möglicherweise die Verwendung von Rails in Betracht ziehen, indem Sie Folgendesmaster
zu IhremGemfile
:Mit dieser neuen Funktion können Sie den Datenbankverbindungspool von Rails nutzen und die Datenbank basierend auf den Bedingungen wechseln.
Ich habe diese neue Funktion nicht verwendet, aber sie scheint ziemlich einfach zu sein:
Sie haben nicht viele Details hinzugefügt, wie Sie die Mandantennummer bestimmen oder wie die Autorisierung in Ihrer Anwendung erfolgt. Aber ich würde versuchen, die Mieternummer so schnell wie möglich in der
application_controller
in einem zu ermittelnaround_action
. So etwas könnte ein Ausgangspunkt sein:quelle
ActiveRecord::Base.connected_to ... do
Block verlassen , wird die Standardverbindung wieder verwendet.master
Filiale enthalten.