In diesem Artikel werden mehrere wichtige Zero-Copy-Technologien in Linux sowie die Szenarien erörtert, in denen Zero-Copy-Technologien anwendbar sind. Um das Konzept von Zero Copy schnell zu etablieren, stellen wir ein gängiges Szenario vor: Zitate Beim Schreiben eines Serverprogramms (Webserver oder Dateiserver) ist das Herunterladen von Dateien eine grundlegende Funktion. Zu diesem Zeitpunkt besteht die Aufgabe des Servers darin, die Datei auf der Server-Host-Festplatte unverändert vom angeschlossenen Socket zu senden. Normalerweise verwenden wir den folgenden Code, um dies abzuschließen: während ((n = lesen (diskfd, buf, BUF_SIZE)) > 0) schreiben(sockfd, buf, n); Die grundlegende Operation besteht darin, den Dateiinhalt zyklisch von der Festplatte in den Puffer zu lesen und dann den Inhalt des Puffers an den Socket zu senden. Die E/A-Vorgänge unter Linux sind jedoch standardmäßig gepufferte E/A. Die beiden hier hauptsächlich verwendeten Systemaufrufe sind Lesen und Schreiben, und wir wissen nicht, was das Betriebssystem darin macht. Tatsächlich werden bei den oben genannten E/A-Vorgängen mehrere Datenkopien erstellt. Wenn eine Anwendung auf ein Datenelement zugreift, prüft das Betriebssystem zunächst, ob die Datei kürzlich aufgerufen wurde und ob der Dateiinhalt im Kernelpuffer zwischengespeichert ist. Wenn dies der Fall ist, kopiert das Betriebssystem den Inhalt des Kernelpuffers direkt in den von buf angegebenen Benutzerspeicherpuffer, basierend auf der vom Systemaufruf read bereitgestellten buf-Adresse. Wenn nicht, kopiert das Betriebssystem zuerst die Daten auf der Festplatte in den Kernelpuffer, der derzeit hauptsächlich auf DMA für die Übertragung angewiesen ist, und kopiert dann den Inhalt des Kernelpuffers in den Benutzerpuffer. Als nächstes kopiert der Systemaufruf „write“ den Inhalt des Benutzerpuffers in den Kernelpuffer, der mit dem Netzwerkstapel verknüpft ist, und schließlich sendet der Socket den Inhalt des Kernelpuffers an die Netzwerkkarte. Nachdem so viel gesagt wurde, ist es besser, das Bild klar zu betrachten: Datenkopie Wie aus der obigen Abbildung ersichtlich, werden insgesamt vier Datenkopien generiert. Selbst wenn DMA zur Abwicklung der Kommunikation mit der Hardware verwendet wird, muss die CPU dennoch zwei Datenkopien verarbeiten. Gleichzeitig treten mehrere Kontextwechsel zwischen Benutzermodus und Kernelmodus auf, was zweifellos die CPU-Belastung erhöht. Was ist Zero-Copy-Technologie? ## Die Hauptaufgabe von Zero Copy besteht darin, zu verhindern, dass die CPU Daten von einer Speichereinheit auf eine andere kopiert. Dabei werden hauptsächlich verschiedene Zero Copy-Technologien verwendet, um zu verhindern, dass die CPU eine große Anzahl von Datenkopieraufgaben ausführt, unnötige Kopiervorgänge zu reduzieren oder diese Art einfacher Datenübertragungsaufgaben von anderen Komponenten ausführen zu lassen, sodass die CPU sich auf andere Aufgaben konzentrieren kann. Dies ermöglicht eine effizientere Nutzung der Systemressourcen. Kehren wir zum Beispiel aus dem vorherigen Artikel zurück. Wie können wir die Anzahl der Datenkopien reduzieren? Ein offensichtlicher Schwerpunkt liegt auf der Reduzierung des Hin- und Herkopierens von Daten zwischen Kernel- und Benutzerbereich, was auch eine Art Nullkopie einführt: Erlaubt die Datenübertragung ohne Umweg über den Benutzerbereich. Verwenden von mmap##### Eine Möglichkeit, die Anzahl der Kopien zu reduzieren, besteht darin, mmap() aufzurufen, anstatt zu lesen: buf = mmap(diskfd, länge); schreiben(sockfd, buf, len); Wenn die Anwendung mmap() aufruft, werden die Daten auf der Festplatte über DMA in den Kernelpuffer kopiert. Das Betriebssystem gibt diesen Kernelpuffer dann an die Anwendung weiter, sodass der Inhalt des Kernelpuffers nicht in den Benutzerspeicher kopiert werden muss. Die Anwendung ruft write() erneut auf und das Betriebssystem kopiert den Inhalt des Kernelpuffers direkt in den Socketpuffer. All dies geschieht im Kernelstatus. Schließlich sendet der Socketpuffer die Daten an die Netzwerkkarte. mmap Die Verwendung von mmap anstelle von read reduziert offensichtlich eine Kopie, was die Effizienz zweifellos verbessert, wenn die Menge der kopierten Daten groß ist. Die Verwendung von mmap ist jedoch mit Kosten verbunden. Bei der Verwendung von mmap können Ihnen einige versteckte Fallstricke begegnen. Wenn Ihr Programm beispielsweise eine Datei zuordnet, die Datei jedoch von einem anderen Prozess abgeschnitten wird, wird der Schreibsystemaufruf aufgrund des Zugriffs auf eine ungültige Adresse durch das SIGBUS-Signal beendet. Standardmäßig beendet das SIGBUS-Signal Ihren Prozess und generiert einen Coredump. Wenn Ihr Server auf diese Weise beendet wird, führt dies zu einem Verlust. Um dieses Problem zu vermeiden, verwenden wir normalerweise die folgenden Lösungen: Erstellen eines Signalhandlers für das SIGBUS-Signal: Wenn ein SIGBUS-Signal erkannt wird, kehrt der Signalhandler einfach zurück, der Systemaufruf „write“ gibt die Anzahl der geschriebenen Bytes zurück, bevor er unterbrochen wurde, und „errno“ wird auf „success“ (Erfolg) gesetzt. Dies ist jedoch keine gute Methode, damit umzugehen, da Sie den Kern des Problems nicht gelöst haben. Verwenden von Datei-Lease-Sperren Wir verwenden diese Methode normalerweise, um Lease-Sperren für Dateideskriptoren zu verwenden. Wir beantragen beim Kernel eine Lease-Sperre für die Datei. Wenn andere Prozesse die Datei kürzen möchten, sendet uns der Kernel in Echtzeit ein RT_SIGNAL_LEASE-Signal, das uns mitteilt, dass der Kernel die Lese-/Schreibsperre zerstört, die Sie für die Datei haben. Auf diese Weise wird Ihr Schreibsystemaufruf unterbrochen, bevor das Programm auf ungültigen Speicher zugreift und von SIGBUS beendet wird. „write“ gibt die Anzahl der geschriebenen Bytes zurück und setzt „errno“ auf „success“. wenn(fcntl(diskfd, F_SETSIG, RT_SIGNAL_LEASE) == -1) { perror("Signal zum Setzen des Kernel-Leases"); Rückgabe -1; } /* l_type kann F_RDLCK F_WRLCK Sperre sein*/ /* l_type kann F_UNLCK-Entsperren sein*/ wenn(fcntl(diskfd, F_SETLEASE, l_Typ)){ perror("Kernel-Lease-Set-Typ"); Rückgabe -1; } Verwenden von sendfile##### Ab der Kernelversion 2.1 führte Linux Sendfile ein, um Vorgänge zu vereinfachen: #include <sys/sendfile.h> ssize_t Sendedatei (int out_fd, int in_fd, off_t *offset, size_t Anzahl); Der Systemaufruf sendfile() überträgt Dateiinhalte (Bytes) zwischen dem Eingabedateideskriptor in_fd und dem Ausgabedateideskriptor out_fd. Der Deskriptor out_fd muss auf einen Socket verweisen, und die Datei, auf die in_fd zeigt, muss mmap-fähig sein. Diese Einschränkungen schränken die Verwendung von sendfile dahingehend ein, dass es nur Daten von einer Datei zu einem Socket übertragen kann, nicht aber umgekehrt. Sendfile-Systemaufrufprozess Was passiert, wenn ein anderer Prozess die Datei abschneidet, wenn wir sendfile aufrufen? Vorausgesetzt, wir legen keine Signalhandler fest, gibt der Sendfile-Aufruf einfach die Anzahl der Bytes zurück, die er vor der Unterbrechung übertragen hat, und errno wird auf „success“ gesetzt. Wenn wir die Datei sperren, bevor wir sendfile aufrufen, verhält sich sendfile genauso wie zuvor und wir erhalten das Signal RT_SIGNAL_LEASE. Bisher haben wir die Anzahl der Datenkopien reduziert, aber es gibt immer noch eine Kopie, nämlich die Kopie vom Seitencache in den Socket-Cache. Können wir diese Kopie also auch weglassen? Mit Hilfe der Hardware können wir es schaffen. Zuvor haben wir die Daten im Seitencache in den Socket-Cache kopiert. Tatsächlich müssen wir nur den Pufferdeskriptor an den Socket-Puffer übergeben und dann die Datenlänge übergeben. Auf diese Weise kann der DMA-Controller die Daten direkt im Seitencache packen und an das Netzwerk senden. Zusammenfassend lässt sich sagen, dass der Systemaufruf sendfile die DMA-Engine verwendet, um den Dateiinhalt in den Kernelpuffer zu kopieren, und dann den Pufferdeskriptor mit den Dateispeicherort- und Längeninformationen zum Socketpuffer hinzufügt. Dieser Schritt kopiert die Daten im Kernel nicht in den Socketpuffer. Die DMA-Engine kopiert die Daten im Kernelpuffer in die Protokoll-Engine und vermeidet so die letzte Kopie. Sendedatei mit DMA Diese Sammel- und Kopierfunktion erfordert allerdings Hardware- und Treiberunterstützung. Splice verwenden##### sendfile ist nur zum Kopieren von Daten aus einer Datei in einen Socket anwendbar, was seinen Anwendungsbereich einschränkt. Linux hat in Version 2.6.17 den Systemaufruf „spleißen“ eingeführt, um Daten zwischen zwei Dateideskriptoren zu verschieben: #define _GNU_SOURCE /* Siehe feature_test_macros(7) */ #include <fcntl.h> ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, vorzeichenlose int-Flags); Der Splice-Aufruf verschiebt Daten zwischen zwei Dateideskriptoren, ohne die Daten zwischen dem Kernel- und dem Benutzerspeicher hin und her zu kopieren. Es kopiert Daten mit der Länge len von fd_in nach fd_out, aber eines der beiden muss ein Pipe-Gerät sein, was derzeit auch eine der Einschränkungen von splice ist. Der Flags-Parameter hat die folgenden Werte:
Der Splice-Aufruf verwendet den von Linux vorgeschlagenen Pipe-Puffermechanismus, daher muss mindestens ein Deskriptor eine Pipe sein. Die oben genannten Zero-Copy-Technologien werden alle implementiert, indem das Kopieren von Daten zwischen Benutzer- und Kernelspeicher reduziert wird. Manchmal müssen Daten jedoch zwischen Benutzer- und Kernelspeicher kopiert werden. Derzeit können wir uns nur auf den Zeitpunkt des Kopierens der Daten zwischen Benutzerbereich und Kernelbereich konzentrieren. Linux verwendet normalerweise Copy-on-Write, um den System-Overhead zu reduzieren, und diese Technologie wird oft als COW bezeichnet. Aus Platzgründen wird in diesem Artikel nicht ausführlich auf Copy-on-Write eingegangen. Grob ausgedrückt: Wenn mehrere Programme gleichzeitig auf dieselben Daten zugreifen, hat jedes Programm einen Zeiger auf diese Daten. Aus der Sicht jedes Programms besitzt es diese Daten unabhängig. Nur wenn das Programm den Dateninhalt ändern muss, wird der Dateninhalt in den eigenen Anwendungsbereich des Programms kopiert. Zu diesem Zeitpunkt werden die Daten zu den privaten Daten des Programms. Wenn das Programm die Daten nicht ändern muss, muss es die Daten nie in seinen eigenen Anwendungsbereich kopieren. Dadurch wird das Kopieren von Daten reduziert. Der Inhalt von Copy-on-Write könnte einen weiteren Artikel füllen. . . Darüber hinaus gibt es einige Zero-Copy-Technologien. Beispielsweise kann durch Hinzufügen der Markierung O_DIRECT zur herkömmlichen Linux-E/A E/A direkt ausgeführt und automatisches Caching vermieden werden. Außerdem gibt es die noch nicht ausgereifte fbufs-Technologie. Dieser Artikel behandelt nicht alle Zero-Copy-Technologien, sondern stellt nur einige gängige vor. Wenn Sie interessiert sind, können Sie sich selbst informieren. Im Allgemeinen ändern ausgereifte Serverprojekte auch die E/A-bezogenen Teile des Kernels selbst, um ihre Datenübertragungsrate zu verbessern. Damit ist dieser Artikel über die Verwendung der Zero-Copy-Technologie in Linux abgeschlossen. Weitere relevante Inhalte zu Linux Zero-Copy finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: JS erzielt Fünf-Sterne-Lobeffekt
>>: Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.21
Inhaltsverzeichnis Vorwort Ziel Erster Schritt: S...
Inhaltsverzeichnis 1. Einleitung 2. Eingabemodus ...
<br />Wenn Sie Musik in eine Webseite einfüg...
In diesem Artikel werden Docker Container (orches...
In diesem Artikelbeispiel wird der spezifische Co...
Inhaltsverzeichnis Überblick Dateideskriptoren Sy...
Im vorherigen Artikel wurde beschrieben, wie man ...
Ich habe in letzter Zeit viele MySQL-Notizen gema...
In diesem Artikel wird der spezifische Code von n...
1. Konzept 1. Der Unterschied zwischen Hot Backup...
1. Einleitung Dieser Artikel enthält keine Screen...
1. CSS-Hintergrund-Tag 1. Stellen Sie die Hinterg...
Was ist ein Baum im Webdesign? Einfach ausgedrückt...
Methode 1: Verwenden Sie den cmd-Befehl Öffnen Si...
Die Implementierungsidee des Javascript-Spiels Sn...