Wow, das ist eine einfache Frage, die eine Vielzahl möglicher Antworten bietet. Im expliziteren Teil Ihrer Frage wird gefragt, ob die direkte oder die über einen Webdienst durchzuführende Schnittstelle mit Ihrer Datenbank skalierbarer ist. Diese Antwort ist einfach: Fragen Sie die Datenbank direkt ab. Durch das Durchlaufen des Webdienstes wird eine ganze Reihe von Wartezeiten hinzugefügt, die für Code, der (im Großen und Ganzen) hinter einer Firewall ausgeführt wird, völlig unnötig sind. Ein Webdienst erfordert beispielsweise, dass eine Komponente eine Anforderung empfängt, sie deserialisiert, die Datenbank abfragt, eine Antwort serialisiert und sie zurückgibt. Wenn Ihr Code also nur hinter einer Firewall ausgeführt wird, sparen Sie sich die Mühe und fragen Sie die Datenbank direkt ab.
Die Skalierbarkeit einer Website geht jedoch weit über die Frage hinaus, die Sie ursprünglich gestellt haben. Verzeihen Sie mir also, wenn ich hier etwas anfange, aber ich dachte, es könnte nützlich sein, wenn man bedenkt, dass Sie insbesondere Facebook erwähnt haben.
Ich würde empfehlen, dass Sie sich über die Arbeit und Tools informieren, die Brad Fitzpatrick (Gründer von LiveJournal und jetzt bei Google) erstellt hat. Als ich bei Six Apart mit ihm zusammengearbeitet habe, habe ich einige Dinge über die Architektur von LiveJournal gelernt, die es so skalierbar gemacht haben.
Verwenden Sie im Gegensatz zu breiten Tabellen schmale Datenbanktabellen . Faszinierend dabei war, zu lernen, was diese Architektur motivierte und ein System schuf, das einfach und schnell waraufgerüstet. Wenn Sie breite Tabellen oder Tabellen verwenden, für die jedes Feld oder jede Eigenschaft eine Spalte in der Tabelle ist, muss das System die Tabelle beim Upgrade des Datenbankschemas sperren, z. B. durch Hinzufügen einer neuen Spalte Änderung wird implementiert. Wenn Sie im Maßstab arbeiten, würde dies bedeuten, dass eine einfache Änderung des Datenbankschemas zu einem großen Datenbankausfall führen könnte. Was offensichtlich scheiße ist. In einer engen Tabelle hingegen wird einfach jede einzelne Eigenschaft, die einem Objekt zugeordnet ist, als einzelne Zeile in der Datenbank gespeichert. Wenn Sie der Datenbank eine neue Spalte hinzufügen möchten, müssen Sie daher nur Datensätze in eine Tabelle einfügen. Dies ist eine nicht sperrende Operation. Ok, das ist ein kleiner Hintergrund. Lassen Sie uns sehen, wie dieses Modell tatsächlich in einem funktionierenden System wie LiveJournal übersetzt wird.
Angenommen, Sie möchten die letzten 10 Journaleinträge in das Blog einer Person laden. Angenommen, jeder Journaleintrag verfügt über zehn Eigenschaften. In einem klassischen breiten Tabellenlayout würde jede Eigenschaft mit einer Spalte in einer Tabelle korrelieren. Ein Benutzer würde dann die Tabelle einmal abfragen, um alle benötigten Daten abzurufen. Die Abfrage würde 10 Zeilen zurückgeben und jede Zeile würde alle Daten enthalten, die sie benötigen (z. B. SELECT * FROM-Einträge ORDER BY-Datum LIMIT 10). Bei einem schmalen Tabellenlayout sieht das jedoch etwas anders aus. In diesem Beispiel gibt es zwei Tabellen: In der ersten Tabelle (Tabelle A) werden einfache Kriterien gespeichert, nach denen gesucht werden soll, z. B. die ID des Eintrags, die ID des Autors, das Datum des Eintrags usw. Eine zweite Tabelle (Tabelle B) speichert dann alle Eigenschaften, die einem Eintrag zugeordnet sind. Diese zweite Tabelle enthält drei Spalten: entry_id, key und value. Für jede Zeile in Tabelle A gibt es 10 Zeilen in Tabelle B (eine Zeile für jede Eigenschaft). Um die letzten zehn Einträge abzurufen und anzuzeigen, benötigen Sie daher 11 Abfragen. Die erste Abfrage enthält die Liste der Eintrags-IDs. Bei den nächsten zehn Abfragen werden die Eigenschaften abgerufen, die den einzelnen in der ersten Abfrage zurückgegebenen Einträgen zugeordnet sind.
"Heiliger Moly!" Sie sagen: "Wie in aller Welt kann das skalierbarer sein ?!" Es ist völlig kontraintuitiv, oder? Im ersten Szenario hatten wir nur eine Datenbankabfrage, aber in der zweiten "skalierbareren" Lösung haben wir 11 Datenbankabfragen. Das macht keinen Sinn. Die Antwort auf diese Frage hängt vollständig von der nächsten Kugel ab.
Verwenden Sie Memcache großzügig. Falls Sie sich dessen nicht bewusst waren, handelt es sich bei memcache um ein verteiltes, zustandsloses, netzwerkbasiertes Caching-System mit geringer Latenz. Es wird von Facebook, Google, Yahoo und nahezu jeder beliebten und skalierbaren Website auf dem Planeten verwendet. Es wurde von Brad Fitzpatrick teilweise erfunden, um den Datenbank-Overhead auszugleichen, der einem Datenbank-Design mit schmalen Tabellen innewohnt. Schauen wir uns das gleiche Beispiel an, wie oben in # 1 beschrieben, aber dieses Mal wollen wir memcache einführen.
Beginnen wir, wenn ein Benutzer zum ersten Mal eine Seite besucht und sich nichts im Cache befindet. Sie beginnen mit der Abfrage der Tabelle A, die die IDs der 10 Einträge zurückgibt, die Sie auf der Seite anzeigen möchten. Für jeden dieser Einträge fragen Sie dann die Datenbank ab, um die diesem Eintrag zugeordneten Eigenschaften abzurufen, und verwenden diese Eigenschaften dann als Objekt, mit dem Ihr Code eine Schnittstelle herstellen kann (z. B. ein Objekt). Anschließend speichern Sie dieses Objekt (oder eine serialisierte Form dieses Objekts) in memcache.
Wenn jemand dieselbe Seite zum zweiten Mal lädt, beginnen Sie auf die gleiche Weise: Durch Abfragen von Tabelle A nach der Liste der angezeigten Eintrags-IDs. Für jeden Eintrag gehen Sie zuerst zu memcache und sagen: "Haben Sie den Eintrag #X im Cache?" Wenn ja, gibt memcache das Eintragsobjekt an Sie zurück. Wenn nicht, müssen Sie die Datenbank erneut abfragen, um ihre Eigenschaften abzurufen, das Objekt zu erstellen und im Memcache zu speichern. Wenn ein Benutzer zum zweiten Mal dieselbe Seite aufruft, gibt es meistens nur eine Datenbankabfrage. Alle anderen Daten werden dann direkt aus dem Memcache abgerufen.
In der Praxis passierte für die meisten LiveJournal-Benutzer, dass die meisten Systemdaten, insbesondere die weniger flüchtigen Daten, im Memcache zwischengespeichert wurden und die zusätzlichen Abfragen an die Datenbank, die zur Unterstützung des Schemas für enge Tabellen erforderlich waren, so gut wie vollständig ausgeglichen wurden.
Dieses Design hat das Lösen des Problems beim Zusammenstellen einer Liste von Posts, die mit all Ihren Freunden verknüpft sind, zu einem Stream oder einer "Wand" sehr viel einfacher gemacht.
Als Nächstes sollten Sie Ihre Datenbank partitionieren. Das oben diskutierte Modell weist noch ein weiteres Problem auf, und das sind Ihre schmalen Tische, die dazu neigen, sehr groß / lang zu sein. Und je mehr Zeilen diese Tabellen enthalten, desto schwieriger werden andere Verwaltungsaufgaben. Um dies auszugleichen, ist es möglicherweise sinnvoll, die Größe Ihrer Tabellen zu verwalten, indem Sie die Tabellen auf eine bestimmte Weise partitionieren, sodass Benutzercluster von einer Datenbank und andere Benutzercluster von einer separaten Datenbank bedient werden. Dies verteilt die Last auf die Datenbank und sorgt für effiziente Abfragen.
Schließlich brauchen Sie tolle Indizes. Die Geschwindigkeit Ihrer Abfragen hängt weitgehend davon ab, wie gut die Tabellen Ihrer Datenbank indiziert sind. Ich werde nicht zu viel Zeit darauf verwenden, zu diskutieren, was ein Index ist, außer zu sagen, dass es einem riesigen Kartenkatalogsystem sehr ähnlich ist, Nadeln in einem Heuhaufen effizienter zu finden. Wenn Sie MySQL verwenden, empfehle ich, das Protokoll für langsame Abfragen zu aktivieren, um zu überwachen, ob Abfragen ausgeführt werden, die lange dauern. Wenn eine Abfrage auf Ihrem Radar erscheint (z. B. weil sie langsam ist), finden Sie heraus, welchen Index Sie zur Tabelle hinzufügen müssen, um sie zu beschleunigen.
"Vielen Dank für all diese großartigen Hintergründe, aber das ist eine Menge Code, den ich schreiben muss."
Nicht unbedingt. Es wurden viele Bibliotheken geschrieben, die die Anbindung an den Memcache sehr einfach machen. Wieder andere Bibliotheken haben den gesamten oben beschriebenen Prozess kodifiziert; Data :: ObjectDriver in Perl ist eine solche Bibliothek. Für andere Sprachen müssen Sie Ihre eigenen Recherchen durchführen.
Ich hoffe, Sie fanden diese Antwort hilfreich. Was ich häufig festgestellt habe, ist, dass die Skalierbarkeit eines Systems häufig immer weniger auf Code und immer mehr auf eine solide Datenspeicherungs- und -verwaltungsstrategie / technisches Design zurückzuführen ist.