Suchen
Schließen Sie dieses Suchfeld.

Windows Storage Offloaded Data Transfer (ODX) und der Fall des fehlenden Prefetch

Geschrieben von:
Wie ein Kunde beim Vergleich von Standard-READ/WRITE mit ODX eine langsamere Leistung als erwartet erlebte – und wie das Engineering-Team die Metriken von Qumulo Core, den schnellen Release-Zyklus und die nahtlose Upgrade-Erfahrung nutzte, um das Rätsel aufzudecken und zu lösen!

Wie ein Kunde beim Vergleich von Standard-READ/WRITE mit ODX eine langsamere Leistung als erwartet erlebte – und wie das Engineering-Team die Metriken von Qumulo Core, den schnellen Release-Zyklus und die nahtlose Upgrade-Erfahrung nutzte, um das Rätsel aufzudecken und zu lösen!

Was ist ODX (Windows Storage Offloaded Data Transfer)?

Windows Storage Offloaded Data Transfer (ODX) ist Teil des Server Message Block (SMB)-Protokolls, mit dem Sie das Qumulo-Dateisystem anweisen können, einen Teil einer Datei von einer Datei in eine andere zu kopieren, ohne die Daten über den Client-Computer zu senden. ODX verbessert die Kopierleistung ähnlich wie serverseitiges Kopieren (SSC). Es eliminiert die Netzwerklatenz zwischen Client und Server und ermöglicht Qumulo Core, IO-Größen und Pufferung zu optimieren. Beim Vergleichen ODX gegen SSC, zeigen unsere internen Testergebnisse, dass ODX 7-mal schneller und SSC 4-mal schneller ist als die typische READ/WRITE-Sequenz, die auftritt, wenn eine Datei an einen anderen Speicherort auf demselben Server kopiert wird.

Lesen Sie das Geheimnis der Latenz

Im Jahr 2021 haben wir ODX-Support für ausgeliefert Qumulo Core Version 3.0.0 oder höher. Kurz nach der Auslieferung berichtete ein Kunde, dass die ODX-Leistung langsamer als erwartet war.

Da wir wussten, dass ODX von einer Datei liest und in eine andere schreibt, vermuteten wir zunächst die Schreibleistung als Problem. Normalerweise dauern Lesevorgänge maximal ein paar Millisekunden (danke SSD-Caching und Prefetching!). Doch als wir uns das ansahen Leselatenz, haben wir gesehen, dass es ein größerer Teil der ODX-Latenz war, als wir vielleicht erwarten – in der Größenordnung von 25 ms (ungefähr), mit höheren Spitzen bis 40 oder 50 ms. Was ist damit los? Hier ist eine Visualisierung der Lebensdauer der Lesephase einer ODX-Operation:

Wir haben uns unsere Zeitreihen-Leistungsdaten mit geringer Granularität angesehen, die wir über unsere Cloud-Überwachungspipeline sammeln. Im Durchschnitt sahen unsere RAM-Cache-Trefferrate und Latenzmetriken gut aus. Aber warum waren dann die ODX-spezifischen Lesevorgänge im Allgemeinen langsam?

Der erste Hinweis

Als wir der Aufdeckung der Grundursache näher kamen, benötigten wir Metriken mit höherer Granularität, die spezifisch für eine einzelne ODX-Workload auf diesem Cluster waren – ohne das Rauschen anderer Vorgänge. Zum Glück haben wir ein Tool namens trigger</var/www/wordpress>, which we built internally, which collects this kind of distributed performance data when needed. We worked with our customer to profile some specific ODX sequences, and used trigger</var/www/wordpress> to collect data during those sequences. We learned a couple of things. (Refer to Figure 1, above.)

Bei jedem Lesevorgang befanden sich die meisten Blöcke im RAM-Cache, aber bei jedem Lesevorgang fehlte für einige Blöcke der Cache. In diesem Fall muss die Dateisystemtransaktion die Daten von den Speichergeräten selbst lesen. In diesem Fall zeigten uns die Metriken, dass sich die Daten auf rotierenden Festplatten befanden.

[box type=“shadow“]Hinweis: In meinem Kopf dachte ich: „Natürlich mussten es die rotierenden Scheiben sein … das sind sie.“ IMMER die rotierenden Scheiben.“ Ich hätte wissen müssen, dass Suchvorgänge das Einzige sind, was die Latenz auf 50 ms hätte erhöhen können. Spinning Disks und ich haben nicht die beste Beziehung. Sie haben die ärgerliche, aber nützliche Angewohnheit, unbeabsichtigtes Verhalten in leistungsempfindlichen Codepfaden schmerzhaft aufzudecken.[/box]

Rotierende Festplatten können Daten effizient streamen, wenn Anforderungen in einer zusammenhängenden Reihenfolge in die Warteschlange gestellt werden. Beginnen Sie am Anfang einer Datei und lesen Sie bis zum Ende. Allerdings fehlten uns in diesem Fall pro ODX-Lesevorgang nur ein paar Blöcke aus dem Cache – was sich auf der rotierenden Festplatte als viele nicht zusammenhängende Lesevorgänge zeigt. Das sind schlechte Nachrichten für die Latenz der sich drehenden Festplatte.

Normalerweise kommt es bei Lesevorgängen im Dateisystem nicht zu dieser Art von Latenz beim Drehen der Festplatte, da wir über einen effektiven Prefetcher verfügen. Der Prefetcher errät, was als nächstes gelesen wird, und lädt es vorab in den Cache. Der Prefetcher verfügt über ein E/A-Muster, das für das Lesen von sich drehenden Festplatten optimiert ist.

Warum funktionierte der Prefetcher also nicht?

Unser Prefetcher verfügt über Kennzahlen, die beschreiben, wie erfolgreich er im Durchschnitt ist. Diese Metriken zeigten uns, dass alles, was vorab abgerufen wurde, gelesen wurde, aber einige Daten, die das Dateisystem las, nicht vorab abgerufen wurden … das ist wirklich seltsam! Vielleicht lesen die ODX-Operationen nicht in der richtigen Reihenfolge oder springen zufällig herum? Der Prefetcher eignet sich nicht gut für zufällige E/A.

Wir haben die Betriebsprotokolle überprüft, um das E/A-Muster zu erkennen. Bei Vorgangsprotokollen handelt es sich um ein Tool für Textprotokolldateien, das uns Informationen zu jedem Vorgang liefert, z. B. Offset, Größe und Cache-Hit oder -Miss. Allerdings hatten wir nicht damit gerechnet, dass wir die ODX-Lesegrößen und -Offsets in unseren Betriebsprotokollen benötigen würden, und deshalb war dieser Code nicht eingebunden! Also mussten wir noch etwas Code schreiben und auf ein Upgrade warten …

Den Täter finden

Innerhalb weniger Wochen hatten wir neuen Code ausgeliefert und mithilfe unserer supertollen Upgrades konnte der Kunde sein Qumulo-Speichersystem kurz darauf auf die neueste Version aktualisieren. Sie haben die Testarbeitslast für uns erneut ausgeführt. Mithilfe der verbesserten Vorgangsprotokollierung haben wir ein weiteres Rätsel gefunden! Durch das Lesen der Betriebsprotokolle (ich hatte das Gefühl, in der Matrix zu sein und die grünen Zahlen zu lesen) stellten wir fest, dass unser ODX-Protokollcode zusammenhängende Leseanforderungen für jeweils 8650752 Bytes an das Dateisystem sendete. Wenn wir nachrechnen, ergibt das 8 Mebibyte + 256 KiB. Aber! Das Betriebsprotokoll zeigte, dass jede ODX-Anfrage tatsächlich nur 8388608 Bytes aus dem Cache erhielt (genau 8 Mebibytes).

Ich erinnere mich, dass meine Augen zuerst glasig wurden. Habe ich die Zahlen falsch verstanden? Wieso fehlt bei jeder Anfrage nur 256 KiB der angeforderten 8 MiB im Cache? Wie ruft der Prefetcher nur eine Teilmenge jeder Anfrage ab? Das ist nicht möglich!

[box type=“shadow“]Hinweis: Die erste Stufe jedes Fehlers ist die Verleugnung – der Glaube, dass die Daten falsch sind. Zum Glück war dies nicht mein erstes Rodeo. Ich unterdrückte schnell meine Ablehnung und begann mich zu fragen: „Wie konnte das möglich sein?“[/box]

Ich begann, meinem Kollegen, der mit mir an der Untersuchung arbeitete, zu erklären, wie der Prefetcher funktioniert. Der Prefetcher sollte der Lese-Workload einen Schritt voraus sein, sodass die E/A-Größe der Lese-Workload keine Rolle spielt. Der Prefetcher ruft Daten immer in großen Blöcken und so ab, dass die Warteschlange auf den rotierenden Festplatten geordnet ist, um Suchvorgänge zu vermeiden. Und dann traf es mich...große Stücke…wie groß sind die Prefetch-Chunks? OH… Sie sind 8 MiB groß … Moment, das ist gruselig. Und wie gelingt es, der Lesearbeitslast einen Schritt voraus zu sein? OH, wir starten einen Prefetch pro Leseanforderung ... Moment ... wenn wir diese beiden Dinge zusammenfügen ... wenn wir nur einen einzelnen Prefetch pro Leseanforderung starten und die Prefetch-Blockgröße höchstens 8 MiB beträgt und der Leser Blöcke von mehr als 8 MiB liest 256 KiB … dann kommt der Prefetcher natürlich nie weiter … er ruft immer die nächsten 8 MiB vorab ab, sodass ein Rest von 256 KiB nicht zwischengespeichert bleibt. BEEINDRUCKEND. (Faustpumpe). OK. Wir haben den rauchenden Beweis gefunden.

Beispieldarstellungen des Prefetch-Problems

Geheimnis erklärt

Den Fehler herauszufinden ist erst der Anfang. Mir kamen sofort drei Fragen in den Sinn:

  1. Warum tritt dieses Problem bei unseren Standard-Dateisystem-Lesetests nicht auf?
  2. Warum verwendet ODX eine E/A-Größe von 8 MiB + 256 KiB, die größer ist als die maximale E/A-Größe des Prefetchers?
  3. Warum haben unsere ODX-spezifischen Leistungstests dies nicht erkannt?
1. Warum tritt dieses Problem bei unseren standardmäßigen Dateisystem-Leseleistungstests nicht auf?

Unser Dateisystem-Protokollplaner verarbeitet alle Protokollanfragen. Die typische Protokollanforderungsgröße beträgt 1 MB. Wenn wir Protokollleseanfragen erhalten, verarbeiten wir diese und kombinieren möglicherweise Anfragen, um die Leseleistung zu optimieren. Wir haben natürlich eine maximale kombinierte IO-Größe für diese Dateisystemanforderungen. Wenn Sie zulassen, dass die E/A-Größe zu groß wird, kann es bei der Anforderung zu einem Engpass bei einer großen Einzelthread-Aktion kommen (z. B. CPU, Speicherzuweisung). Unser Dateisystem-Scheduler sorgt also dafür, dass die maximale kombinierte Leseanforderung 8 MB beträgt, was der maximalen E/A-Größe unseres Prefetchers entspricht. Das war beabsichtigt. Bei diesen Workloads ruft der Prefetcher also alles vorab ab, obwohl er nie mehr als 8 MiB voranbringt, wenn die kombinierte E/A-Größe ebenfalls 8 MiB beträgt…(kratzt sich am Kopf...das war auch kein beabsichtigtes Verhalten...).

2. Warum verwendet ODX eine IO-Größe von 8 MiB + 256 KiB?

Der ODX-Vorgang selbst durchläuft den Scheduler, übermittelt jedoch nicht seine interne Leseanforderung über den Scheduler. ODX legte dann die maximale E/A-Lesegröße fest, die es unabhängig vom Scheduler anfordern würde.

Wir haben festgestellt, dass die maximale E/A-Größe des Schedulers und die maximale E/A-Größe des ODX unterschiedliche Funktionen verwendeten:

fs_target_transaction_size()
fs_max_transaction_size()</var/www/wordpress>

Der verwendete Planer fs_target_transaction_size</var/www/wordpress>, which is a minimum of fs_max_transaction_size</var/www/wordpress> and 8MiB! Whereas the ODX code was intuitively using fs_max_transaction_size</var/www/wordpress> - which is computed, and turned out to be 8MiB + 256KiB.

Da war also unsere Grundursache. Wir haben den zu verwendenden ODX-Protokollcode festgelegt fs_target_transaction_size</var/www/wordpress>, and voilà, no more uncached tails to the read requests.

3. Warum haben unsere Leistungstests von ODX dies nicht erkannt?

Unsere ODX-Leistungstests war zeigen tatsächlich das Verhalten von nicht zwischengespeicherten Enden. Aber die Leistung war nicht so schlecht; Denn bei diesem Leistungstest waren die Daten klein genug, um in den SSD-Cache zu passen!

Rückblickend Figure 1 (oben) können Sie sehen, dass die Latenz beim Lesen von SSD viel geringer ist als bei rotierenden Festplatten. Aus den Top-Performance-Testergebnissen war also nicht so offensichtlich, dass der Prefetcher das Falsche tat. Der Test überprüfte die Metriken des Prefetchers nicht explizit.

Nachdem wir den Leistungstest dahingehend geändert hatten, dass in einem zweiten Schritt die Daten von der SSD entfernt und dann von der rotierenden Festplatte zurückgelesen wurden, war die Gesamtleistung deutlich schlechter als sie hätte sein sollen – was den Fehler aufdeckte. Wir haben den Fehler behoben, eine Verbesserung dieses automatisierten Leistungstests beobachtet und Die Verbesserung wurde innerhalb von 2 Wochen versandt. Noch einmal die Vorteile von Qumulo nutzen einfache Upgradeskonnten unsere Kunden schon bald nach dem Fix ein Upgrade durchführen und von der verbesserten ODX-Leistung profitieren.

Mehr erfahren

Verwandte Artikel

Nach oben scrollen