it-swarm.com.de

Sind mehrere Datenbankaufrufe bei einem Netzwerkaufruf für eine Web-API wirklich wichtig?

Bei einem meiner Arbeitgeber haben wir an einer API REST (gilt aber auch für SOAP)) gearbeitet. Der Client, bei dem es sich um die Benutzeroberfläche der Anwendung handelt, hat Anrufe über das Web getätigt (LAN in der typischen Produktion) Bereitstellungen) an die API. Die API ruft die Datenbank auf.

Ein Thema, das in unseren Diskussionen immer wieder vorkommt, ist die Leistung: Einige Mitarbeiter des Teams sind der Ansicht, dass Sie aufgrund der Leistung nicht mehrere Datenbankaufrufe (normalerweise Lesevorgänge) von einem einzelnen API-Aufruf ausführen sollten. Sie sollten sie so optimieren, dass jeder API-Aufruf nur (genau) einen Datenbankaufruf enthält.

Aber ist das wirklich wichtig? Beachten Sie, dass die Benutzeroberfläche einen Netzwerkaufruf an die API ausführen muss. das ist ziemlich groß (Größenordnung von Millisekunden). Datenbanken sind so optimiert, dass die Dinge im Speicher bleiben und Lesevorgänge sehr, sehr schnell ausgeführt werden (z. B. SQL Server lädt und speichert alles in RAM und verbraucht fast alle Ihre freien RAM) = wenn es geht).

TLDR: Ist es wirklich wichtig, sich über mehrere Datenbankaufrufe Gedanken zu machen, wenn wir bereits einen Netzwerkanruf über das LAN tätigen? Wenn ja, warum?

Um es klar auszudrücken, ich spreche von einer Größenordnung - ich weiß, dass dies von Besonderheiten abhängt (Maschinenhardware, Auswahl von API und DB usw.). Wenn ich einen Aufruf habe, der O (Millisekunden) dauert, wird für DB optimiert Anrufe, die eine Größenordnung weniger dauern, sind eigentlich wichtig? Oder hat das Problem mehr zu bieten?

Edit : Für die Nachwelt finde ich es ziemlich lächerlich zu behaupten, dass wir die Leistung verbessern müssen, indem wir Datenbankaufrufe unter diesen Umständen kombinieren - insbesondere mit einem Mangel an Profilen. Es ist jedoch nicht meine Entscheidung, ob wir dies tun oder nicht; Ich möchte wissen, was der Grund dafür ist, dass dies eine korrekte Methode zur Optimierung von Web-API-Aufrufen ist.

16
ashes999

Aber ist das wirklich wichtig? Beachten Sie, dass die Benutzeroberfläche einen Netzwerkaufruf an die API ausführen muss. das ist ziemlich groß (Größenordnung von Millisekunden). Datenbanken sind so optimiert, dass die Dinge im Speicher bleiben und Lesevorgänge sehr, sehr schnell ausgeführt werden (z. B. SQL Server lädt und speichert alles in RAM und verbraucht fast alle Ihre freien RAM) = wenn es geht).

Die Logik

Theoretisch sind Sie richtig. Es gibt jedoch einige Mängel bei dieser Begründung:

  1. Nach Ihren Angaben ist unklar, ob Sie Ihre App tatsächlich getestet/profiliert haben. Mit anderen Worten, wissen Sie tatsächlich , dass die Netzwerkübertragungen von der App zur API die langsamste Komponente sind? Da dies intuitiv ist, kann man leicht davon ausgehen, dass dies der Fall ist. Wenn Sie jedoch über die Leistung sprechen, sollten Sie niemals davon ausgehen. Bei meinem Arbeitgeber bin ich der Leistungsleiter. Als ich anfing, sprachen die Leute immer wieder über CDNs, Replikationen usw., basierend auf der Intuition, was die Engpässe sein müssen. Es stellte sich heraus, dass unsere größten Leistungsprobleme darin bestanden, Datenbankabfragen schlecht durchzuführen.

  2. Sie sagen, weil Datenbanken gut Daten abrufen können, dass die Datenbank notwendigerweise mit maximaler Leistung ausgeführt wird, optimal genutzt wird und nichts getan werden kann, um sie zu verbessern. Mit anderen Worten, Datenbanken sind so konzipiert, dass sie schnell sind, sodass ich mir keine Sorgen machen muss. Eine weitere gefährliche Denkrichtung. Das ist so, als würde man sagen, ein Auto soll sich schnell bewegen, also muss ich das Öl nicht wechseln.

  3. Diese Denkweise setzt jeweils einen einzelnen Prozess voraus oder anders ausgedrückt, keine Parallelität. Es wird davon ausgegangen, dass eine Anforderung die Leistung einer anderen Anforderung nicht beeinflussen kann. Ressourcen werden gemeinsam genutzt, z. B. Festplatten-E/A, Netzwerkbandbreite, Verbindungspools, Speicher, CPU-Zyklen usw. Durch die Reduzierung der Verwendung einer gemeinsam genutzten Ressource durch einen Datenbankaufruf kann daher verhindert werden, dass andere Anforderungen langsamer werden. Als ich zum ersten Mal zu meinem derzeitigen Arbeitgeber kam, war das Management der Ansicht, dass das Optimieren einer 3-Sekunden-Datenbankabfrage Zeitverschwendung war. 3 Sekunden sind so wenig, warum Zeit damit verschwenden? Wären wir nicht besser dran mit einem CDN oder einer Komprimierung oder etwas anderem? Wenn ich jedoch eine 3-Sekunden-Abfrage in 1 Sekunde ausführen kann, z. B. durch Hinzufügen eines Index, bedeutet dies 2/3 weniger Blockierung, 2/3 weniger Zeit für die Besetzung eines Threads und vor allem weniger Daten, die von der Festplatte gelesen werden Es werden weniger Daten aus dem RAM-Cache gelöscht.

Theorie

Es gibt eine verbreitete Auffassung, dass es bei der Softwareleistung einfach um Geschwindigkeit geht.

Aus rein geschwindigkeitlicher Sicht haben Sie recht. Ein System ist nur so schnell wie seine langsamste Komponente. Wenn Sie Ihren Code profiliert haben und festgestellt haben, dass das Internet die langsamste Komponente ist, ist alles andere offensichtlich nicht der langsamste Teil.

Angesichts der obigen Ausführungen hoffe ich jedoch, dass Sie sehen können, wie Ressourcenkonflikte, fehlende Indizierung, schlecht geschriebener Code usw. zu überraschenden Leistungsunterschieden führen können.

Die Annahmen

Eine letzte Sache. Sie haben erwähnt, dass ein Datenbankaufruf im Vergleich zu einem Netzwerkaufruf von der App zur API günstig sein sollte. Sie haben aber auch erwähnt, dass sich die App und die API-Server im selben LAN befinden. Sind beide nicht als Netzwerkanrufe vergleichbar? Mit anderen Worten, warum nehmen Sie an, dass die API-Übertragung um Größenordnungen langsamer ist als die Datenbankübertragung, wenn beide dieselbe verfügbare Bandbreite haben? Natürlich sind die Protokolle und Datenstrukturen unterschiedlich, das verstehe ich, aber ich bestreite die Annahme, dass sie um Größenordnungen unterschiedlich sind.

Wo es murkey wird

Diese ganze Frage bezieht sich auf "mehrere" versus "einzelne" Datenbankaufrufe. Es ist jedoch unklar, wie viele mehrere sind. Aufgrund der obigen Ausführungen empfehle ich als Faustregel, so wenige Datenbankaufrufe wie nötig durchzuführen. Das ist aber nur eine Faustregel.

Hier ist warum:

  1. Datenbanken können Daten hervorragend lesen. Sie sind Speichermotoren. Ihre Geschäftslogik lebt jedoch in Ihrer Anwendung. Wenn Sie die Regel festlegen, dass jeder API-Aufruf genau zu einem Datenbankaufruf führt, wird Ihre Geschäftslogik möglicherweise in der Datenbank gespeichert. Vielleicht ist das ok Viele Systeme machen das. Aber manche nicht. Es geht um Flexibilität.
  2. Manchmal möchten Sie, um eine gute Entkopplung zu erreichen, zwei Datenbankaufrufe trennen. Beispielsweise wird möglicherweise jede HTTP-Anforderung über einen generischen Sicherheitsfilter weitergeleitet, der anhand der Datenbank überprüft, ob der Benutzer über die richtigen Zugriffsrechte verfügt. Wenn dies der Fall ist, führen Sie die entsprechende Funktion für diese URL aus. Diese Funktion kann mit der Datenbank interagieren.
  3. Aufruf der Datenbank in einer Schleife. Deshalb habe ich gefragt, wie viele mehrfach sind. Im obigen Beispiel hätten Sie 2 Datenbankaufrufe. 2 ist in Ordnung. 3 kann in Ordnung sein. N ist nicht gut. Wenn Sie die Datenbank in einer Schleife aufrufen, haben Sie die Leistung jetzt linearisiert. Dies bedeutet, dass es umso länger dauert, je mehr Eingaben in der Schleife enthalten sind. Wenn Sie also kategorisch sagen, dass die API-Netzwerkzeit die langsamste ist, werden Anomalien wie 1% Ihres Datenverkehrs aufgrund einer noch nicht entdeckten Schleife, die die Datenbank 10.000 Mal aufruft, vollständig übersehen.
  4. Manchmal gibt es Dinge, in denen Ihre App besser ist, wie beispielsweise komplexe Berechnungen. Möglicherweise müssen Sie einige Daten aus der Datenbank lesen, einige Berechnungen durchführen und dann basierend auf den Ergebnissen einen Parameter an einen zweiten Datenbankaufruf übergeben (möglicherweise, um einige Ergebnisse zu schreiben). Wenn Sie diese zu einem einzigen Aufruf (wie einer gespeicherten Prozedur) zusammenfassen, um die Datenbank nur einmal aufzurufen, haben Sie sich gezwungen, die Datenbank für etwas zu verwenden, in dem der App-Server möglicherweise besser ist.
  5. Lastausgleich: Sie haben (vermutlich) 1 Datenbank und mehrere Anwendungsserver mit Lastausgleich. Je mehr Arbeit die App leistet und je weniger die Datenbank leistet, desto einfacher ist die Skalierung, da das Hinzufügen eines App-Servers im Allgemeinen einfacher ist als das Einrichten der Datenbankreplikation. Basierend auf dem vorherigen Aufzählungspunkt kann es sinnvoll sein, eine SQL-Abfrage auszuführen, dann alle Berechnungen in der Anwendung durchzuführen, die auf mehrere Server verteilt ist, und dann die Ergebnisse zu schreiben, wenn Sie fertig sind. Dies könnte zu einem besseren Durchsatz führen (selbst wenn die gesamte Transaktionszeit gleich ist).

TL; DR

TLDR: Ist es wirklich wichtig, sich über mehrere Datenbankaufrufe Gedanken zu machen, wenn wir bereits einen Netzwerkanruf über das LAN tätigen? Wenn ja warum?

Ja, aber nur bis zu einem gewissen Grad. Sie sollten versuchen, die Anzahl der Datenbankaufrufe so gering wie möglich zu halten, aber keine Aufrufe kombinieren, die nichts miteinander zu tun haben, nur um sie zu kombinieren. Vermeiden Sie außerdem um jeden Preis das Aufrufen der Datenbank in einer Schleife.

25
Brandon

Klingt so, als würde Ihr Team optimieren, bevor es einen Grund dazu hat. Haben Sie die Zeit gemessen, um diese Anforderungen auszuführen? Die Wahrscheinlichkeit, dass dieses Paradigma erzwungen wird, führt zu einer schlechteren Leistung für den Endbenutzer, da die Roundtrips zum Webserver eine viel höhere Latenz aufweisen als die Verbindungszeit vom Webserver zur Datenbank. Darüber hinaus stellen die meisten Webbrowser nur zwei gleichzeitige Verbindungen zu einem einzelnen Webserver her, sodass bei komplexen Seiten dort wahrscheinlich ein Engpass auftritt.

In beiden Fällen sollten Optimierungsentscheidungen nicht ohne Daten getroffen werden, um sie zu sichern. Messen Sie es und finden Sie heraus, was für Ihre Anwendung am besten ist.

3
brianfeucht

Wir können es dir nicht sagen.

Wir wissen nicht, wie Ihre Anfragen aussehen. Wir wissen nicht, wie lange sie dauern. Wir wissen nicht, wie viel Overhead mit jeder Anforderung an Ihren API-Server verbunden ist. Wir wissen nicht, wie geografisch Ihre Kunden verteilt sind. usw.

Wenn dies ein Szenario ist, das optimiert werden muss und in dem Sie können Entscheiden Sie, ob die Aufrufe aufgeteilt oder zusammengefügt werden sollen, Sie müssen sie in beide Richtungen vergleichen: Entscheiden Sie, wofür Sie optimieren (UI-Latenz, Server-CPU-Auslastung, Konflikte usw.) und wählen Sie den aus derjenige, der Ihr Optimierungsziel besser erreicht.


Abgesehen davon ist das einzige einzige , was ich mit relativer Sicherheit hinzufügen kann, Folgendes:

Innerhalb einer einzelnen Anforderung sollten Sie alle Abfragen ausführen, die Sie zum Erstellen einer Antwort ausführen müssen.

Mit anderen Worten, wenn die Antwort erst generiert werden kann, wenn alle N Abfragen ausgeführt wurden, ist es normalerweise sinnlos, sie zu trennen. Wenn Sie nach jeder Abfrage aussagekräftige Ergebnisse erzielen können, egal ob mittelschwer oder vollständig, starten Sie das Benchmarking.

2
svidgen

Zwei Gedanken:

Zunächst ruft der Verbraucher, der die API verwendet, einen Anruf an, um eine Aufgabe auszuführen. Was passiert, nachdem Ihr Server den Anruf zum Ausfüllen der Anforderung erhalten hat, sollte nicht so starr sein. Wenn für diesen einen Anruf eines Verbrauchers 10 Unterarbeitselemente erforderlich sind, um die Daten zusammenzuführen und zurückzugeben, sollte dies akzeptabel sein.

Zweitens: Sehen Sie ein tatsächliches Datenbankleistungsproblem mit dem betreffenden Prozess? Meine Erfahrung hat gezeigt, dass der Versuch, alle Aspekte einer Datenbankanforderung in einem einzigen Anruf zusammenzufassen, zu einem weniger effizienten Anruf führen kann, als nur drei oder vier Datenanrufe zu tätigen. Moderne Datenbanken sind sehr effizient in Caching- und Ausführungsplänen. Wenn Sie versuchen, zu viel zu tun, sehen Sie häufig Prozeduren mit Cursorn (sehr schlecht für die Leistung, da Daten zeilenweise und nicht als Satz auf einmal verarbeitet werden) und Code, der zu einem weniger effizienten Plan führt, als wenn Sie gebrochen hätten Der Aufruf erfolgt in mehreren kleinen einfachen Schritten.

Aufgrund der einfachen Organisation des Codes stimme ich zu, dass jeder API-Aufruf möglicherweise eine einzelne gespeicherte Prozedur (oder DB-Funktion) aufrufen sollte, die wiederum für das Ausfüllen der Anforderung verantwortlich ist. Das Verfahren kann mehr als einen Schritt umfassen.

1
Richard

Wenn sich die Datenbank auf einem anderen Server befindet als Ihr REST -Dienst), führt jeder Datenbankaufruf zu einem Netzwerk-Roundtrip, und kann die Leistung erheblich beeinträchtigen:

Ich habe einmal beobachtet, dass ein einzelner Webservice-Aufruf in etwa 500 Datenbankabfragen übersetzt wurde - dies war kaum ein Problem, wenn sich sowohl der Webservice als auch die Datenbank auf demselben Computer befanden, aber sich in einer Antwortzeit von 6-7 Sekunden befanden, wenn sie sich auf verschiedenen Computern befanden Maschinen.

Offensichtlich sind 500 Roundtrips zur Datenbank ziemlich extrem. Ich bin mir nicht sicher, wie hoch Ihre Leistungsanforderungen sind, aber als Faustregel würde ich sagen, dass Sie keinen signifikanten Leistungseinbruch erleben sollten, wenn Sie unter etwa 10 Datenbankabfragen pro REST-Aufruf bleiben.

1
Astrotrain

Wir haben einige Anwendungen, die sehr, sehr gesprächig sind. Für jeden gibt es einen Datenbankaufruf. Single. Wenig. Ding. Das wiederholte Bereitstellen von Referenzdaten ist ein wesentlicher Teil der Arbeitslast des Systems. Die gesamte Planung von Worker-Threads, das Erfassen und Löschen von Sperren, das Planen der Cache-Überprüfung usw. summiert sich, selbst wenn keine tatsächliche Festplatten-E/A vorhanden ist. Die Konkurrenz ist höher, da Transaktionen Sperren für mehrere DB-Aufrufe halten müssen und der Durchsatz daher viel geringer ist, als er sein könnte. Aus diesem Grund müssen diese Teams jetzt neue, sehr teure DB-Server kaufen.

Obwohl der Großteil der in der aktuellen Konfiguration Ihres Systems verstrichenen Zeit mit REST API-Aufrufe) verbracht wird, speichert das Ignorieren der Leistung auf DB-Ebene Probleme für die Zukunft.

1
Michael Green

Der dargestellte Optimierungspfad ist einfach die falsche Sichtweise.

API-Aufrufe sollten atomar sein. Mit anderen Worten, ich sollte in der Lage sein, einen Web-API-Aufruf auszuführen, um die gewünschte Aktion auszuführen. Ob das Daten abrufen, einen Datensatz aktualisieren oder was auch immer. Es sollte NIEMALS mehr als einen Anruf dauern, um die Aktion auszulösen. Der Versuch, Transaktionen über mehrere Anrufe hinweg zu nutzen, sollte wie die Pest gemieden werden.

Manchmal ist eine einzelne Aktion ziemlich komplex. Zum Beispiel das Abrufen von Daten, die aus mehreren Quellen kombiniert wurden: Auch dies sollte ein einzelner Aufruf sein. Entweder funktioniert das Ganze oder das Ganze versagt.

Zu sagen, dass ein einzelner API-Aufruf nur eine DB-Abfrage ausführen sollte, ist etwas schwachsinnig. Wie Sie bereits betont haben, ist der Aufwand für das Rangieren des Anrufs über das Netzwerk in Bezug auf die Gesamtzeit häufig um Größenordnungen teurer.

Ich kann etwas ihre Aussage verstehen, dass eine einzelne Abfrage schneller ausgeführt werden kann als mehrere; Dies vermittelt jedoch einen falschen Eindruck, da die gesamte Datenbank- und Netzwerklast ignoriert wird. Nur wenn Sie die verschiedenen Möglichkeiten zum Abrufen von Daten aus der Datenbank profilieren, können Sie herausfinden, wo das Problem wirklich liegt. Ich bin sicher, jeder hat eine Geschichte, in der eine bestimmte Abfrage, die 100 Mal häufiger als erwartet ausgeführt wurde, das System tötete, bis ein geeigneter Index eingerichtet wurde ...

Letztendlich werden Sie sie nicht mit nur Reden überzeugen können. Richten Sie einen Testfall für beide Ansätze ein und profilieren Sie sie. Achten Sie auf die Gesamtzeit für die Erfassung der benötigten Daten, die Menge des generierten Netzwerkverkehrs, die Anzahl und das Timing der Datenbankaufrufe usw. Gehen Sie ganzheitlich vor - das heißt, Sie betrachten das gesamte System - und Sie sollten am Ende genügend Daten haben Daten, um entweder Krähe zu essen oder ihnen den goldenen Weg zu zeigen.

0
NotMe