Bei einem meiner Arbeitgeber haben wir an einer REST-API gearbeitet (dies gilt jedoch auch für SOAP). Der Client, bei dem es sich um die Benutzeroberfläche der Anwendung handelt, ruft die API über das Web (LAN in typischen Produktionsbereitstellungen) auf. Die API ruft die Datenbank auf.
Ein Thema, das sich in unseren Diskussionen wiederholt, ist die Leistung: Einige Teammitglieder sind der Ansicht, dass Sie aus Leistungsgründen nicht mehrere Datenbankaufrufe (normalerweise Lesezugriffe) von einem einzelnen API-Aufruf aus durchführen sollten. Sie sollten sie so optimieren, dass jeder API-Aufruf nur (genau) einen Datenbankaufruf hat.
Aber ist das wirklich wichtig? Bedenken Sie, dass die Benutzeroberfläche einen Netzwerkaufruf an die API durchführen muss. das ist ziemlich groß (Größenordnung von Millisekunden). Datenbanken sind optimiert, um den Arbeitsspeicher zu erhalten und Lesevorgänge sehr, sehr schnell auszuführen (z. B. SQL Server lädt und speichert alles im Arbeitsspeicher und belegt fast den gesamten freien Arbeitsspeicher, wenn dies möglich ist).
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 der Größenordnung - ich weiß, dass es von Besonderheiten abhängt (Maschinenhardware, Auswahl der API und der Datenbank usw.) Anrufe, die eine Größenordnung kleiner sind, sind eigentlich wichtig? Oder gibt es mehr zum Problem als dieses?
Edit: Für die Nachwelt halte ich es für ziemlich lächerlich, zu behaupten, dass wir die Leistung verbessern müssen, indem wir Datenbankaufrufe unter diesen Umständen kombinieren - insbesondere bei fehlender Profilerstellung. Es ist jedoch nicht meine Entscheidung, ob wir dies tun oder nicht; Ich möchte wissen, welche Gründe dafür sprechen, dass dies eine korrekte Methode zur Optimierung von Web-API-Aufrufen ist.
quelle
Antworten:
Die Logik
Theoretisch hast du recht. Es gibt jedoch ein paar Fehler mit dieser Begründung:
Nach Ihren Angaben ist nicht klar, 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, ist es leicht anzunehmen, dass dies der Fall ist. Wenn Sie jedoch über die Leistung sprechen, sollten Sie niemals davon ausgehen. Bei meinem Arbeitgeber bin ich der Leistungsführer. Als ich anfing, redeten die Leute über CDNs, Replikation usw., basierend auf der Intuition darüber, was die Engpässe sein müssen. Es stellte sich heraus, dass unsere größten Leistungsprobleme darin bestanden, Datenbankabfragen schlecht durchzuführen.
Sie sagen, dass, weil Datenbanken Daten gut abrufen können, 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 darüber keine Sorgen machen sollte. Eine weitere gefährliche Denkrichtung. Das ist, als würde man sagen, ein Auto soll sich schnell bewegen, damit ich das Öl nicht wechseln muss.
Diese Denkweise geht von einem einzelnen Prozess aus, oder anders ausgedrückt, von keiner Nebenläufigkeit. 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, Arbeitsspeicher, CPU-Zyklen usw. Daher kann die Reduzierung der Nutzung einer gemeinsam genutzten Ressource durch einen Datenbankaufruf verhindern, dass andere Anforderungen verlangsamt werden. Als ich zum ersten Mal zu meinem derzeitigen Arbeitgeber kam, war das Management der Ansicht, dass die Optimierung einer Datenbankabfrage von 3 Sekunden Zeitverschwendung war. 3 Sekunden sind so wenig, warum Zeit darauf verschwenden? Wären wir mit einem CDN oder einer Komprimierung oder etwas anderem nicht besser dran? Wenn ich jedoch eine 3-Sekunden-Abfrage in 1 Sekunde ausführen kann, indem ich beispielsweise einen Index hinzufüge, der 2/3 weniger blockiert, 2/3 weniger Zeit für das Besetzen eines Threads benötigt und vor allem weniger Daten von der Festplatte liest,
Die Theorie
Es gibt eine verbreitete Vorstellung, dass es bei der Software-Leistung einfach um Geschwindigkeit geht .
Sie haben aus reiner Geschwindigkeitsperspektive 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.
Ich hoffe jedoch, dass Sie in Anbetracht der obigen Ausführungen sehen können, wie Ressourcenkonflikte, mangelnde Indizierung, schlecht geschriebener Code usw. zu überraschenden Leistungsunterschieden führen können.
Die Annahmen
Eine letzte Sache. Sie erwähnten, 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 sie also nicht beide vergleichbar mit Netzanrufen? 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 es sich um Größenordnungen handelt, die sich unterscheiden.
Wo es Murkey bekommt
Bei dieser ganzen Frage geht es um "mehrere" oder "einzelne" Datenbankaufrufe. Es ist jedoch unklar, wie viele mehrere sind. Aufgrund der oben genannten allgemeinen Faustregel empfehle ich, so wenig Datenbankaufrufe wie nötig durchzuführen. Das ist aber nur eine Faustregel.
Hier ist warum:
TL; DR
Ja, aber nur bis zu einem gewissen Grad. Sie sollten versuchen, die Anzahl der Datenbankaufrufe zu minimieren, wenn dies sinnvoll ist. Kombinieren Sie jedoch keine Aufrufe, die nichts miteinander zu tun haben, nur um sie zu kombinieren. Vermeiden Sie außerdem, die Datenbank unter allen Umständen in einer Schleife aufzurufen.
quelle
Klingt so, als würde Ihr Team optimieren, bevor es einen Grund dazu hat. Haben Sie die Zeit gemessen, um diese Anforderungen auszuführen? Es besteht die Möglichkeit, dass dieses Paradigma zu einer schlechteren Leistung für den Endbenutzer führt, da 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 zur Sicherung getroffen werden. Messen Sie es und finden Sie heraus, was für Ihre Anwendung am besten ist.
quelle
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 Aufwand mit jeder Anforderung an Ihren API-Server verbunden ist. Wir wissen nicht, wie geografisch Ihre Kunden verteilt sind. Etc.
Wenn dies ein Szenario ist, das optimiert werden muss und in dem Sie entscheiden können , ob Sie die Anrufe aufteilen oder zusammenführen möchten, müssen Sie es auf beide Arten vergleichen : Entscheiden Sie, für was Sie optimieren (Wartezeit auf der Benutzeroberfläche, Server-CPU-Auslastung, Konflikte, usw.) und wählen Sie die aus, die Ihr Optimierungsziel besser erreicht.
Abgesehen davon ist das Einzige , was ich mit relativer Sicherheit hinzufügen kann:
Innerhalb einer einzelnen Anforderung sollten Sie alle Abfragen ausführen, die zum Erstellen einer Antwort erforderlich sind.
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, starten Sie das Benchmarking.
quelle
Zwei Gedanken:
Erstens tätigt der Verbraucher, der die API verwendet, einen einzigen Aufruf, um eine Aufgabe auszuführen. Was passiert, nachdem Ihr Server den Anruf zum Befüllen der Anfrage erhalten hat, sollte nicht so starr sein. Wenn für diesen einen Anruf eines Verbrauchers 10 Unteraufgaben erforderlich sind, um die Daten zusammenzuführen und zurückzugeben, sollte dies akzeptabel sein.
Zweitens: Wird bei dem betreffenden Prozess ein tatsächliches Problem mit der Datenbankleistung festgestellt? 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 wenn lediglich drei oder vier Datenanrufe getätigt werden. Moderne Datenbanken sind in Caching- und Ausführungsplänen sehr effizient. Wenn Sie versuchen, zu viel zu tun, sehen Sie häufig Prozeduren mit Cursorn (sehr schlecht für die Leistung, da die Daten zeilenweise und nicht als Satz gleichzeitig verarbeitet werden) und Code, der zu einem weniger effizienten Plan führt, als wenn Sie dies getan hätten Der Aufruf erfolgt in mehreren kleinen einfachen Schritten.
Aus Gründen 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.
quelle
SELECT
.Befindet sich die Datenbank auf einem anderen Server als Ihr REST-Service, führt jeder Datenbankaufruf zu einem Netzwerk-Roundtrip, was die Leistung erheblich beeinträchtigen kann:
Ich habe einmal beobachtet, dass ein einziger 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 wenn sie sich auf einem anderen Computer befanden, wurde daraus eine Antwortzeit von 6-7 Sekunden maschinen.
Offensichtlich sind 500 Roundtrips in die 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 10 Datenbankabfragen pro REST-Aufruf bleiben.
quelle
Wir haben ein paar Anwendungen, die sehr, sehr gesprächig sind. Es gibt für jeden einen Datenbankaufruf. Single. Wenig. Sache. Das wiederholte Bereitstellen von Referenzdaten ist ein wichtiger Teil der Arbeitsbelastung des Systems. Die gesamte Zeitplanung für Worker-Threads, das Erfassen und Löschen von Sperren, das Planen der Cache-Überprüfung usw. summiert sich auch dann, wenn keine tatsächliche Platten-E / A vorhanden ist. Die Konkurrenz ist höher, da Transaktionen Sperren über mehrere DB-Aufrufe hinweg 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-Aufrufen verbracht wird, werden durch das Ignorieren der Leistung auf DB-Ebene Probleme für die Zukunft gespeichert.
quelle
Der dargestellte Optimierungspfad ist einfach die falsche Betrachtungsweise.
API-Aufrufe sollten atomar sein. Mit anderen Worten, ich sollte in der Lage sein, 1 Web-API-Aufruf durchzuführen, um die gewünschte Aktion auszuführen. Ob das zum Abrufen von Daten, Aktualisieren eines Datensatzes oder was auch immer ist. Es sollte NIEMALS mehr als ein Anruf erfolgen, um die Aktion auszulösen. Und der Versuch, Transaktionen über mehrere Anrufe hinweg wirksam einzusetzen, 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 scheitert.
Nun zu sagen, dass ein einzelner API-Aufruf nur eine DB-Abfrage ausführen sollte, ist ein bisschen schwachsinnig. Wie Sie bereits betont haben, ist der Aufwand für die Vermittlung des Anrufs über das Netzwerk im Hinblick auf die Gesamtzeit häufig um Größenordnungen höher.
Ich kann ihre Aussage einigermaßen verstehen, dass eine einzelne Abfrage schneller als mehrere ausgeführt werden kann; Dies gibt jedoch einen falschen Eindruck, da die gesamte Datenbank- und Netzwerklast ignoriert wird. Nur durch Profilerstellung der verschiedenen Methoden zum Abrufen von Daten aus der Datenbank können Sie das eigentliche Problem ermitteln. Ich bin sicher, jeder hat eine Geschichte, in der eine bestimmte Abfrage 100-mal häufiger als erwartet ausgeführt wurde und das System bis zur Einrichtung eines richtigen Index zum Erliegen gebracht hat ...
Letztendlich werden Sie sie nicht nur durch Gespräche ü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 von Ihnen benötigten Daten, die Menge des generierten Netzwerkverkehrs, die Anzahl und den Zeitpunkt der Datenbankaufrufe usw. Nehmen Sie einen ganzheitlichen Ansatz - das heißt, Sie betrachten das gesamte System - und Sie sollten am Ende eine Menge davon haben Daten, um entweder Krähe zu essen oder ihnen den goldenen Weg zu zeigen.
quelle