Heim  >  Artikel  >  Datenbank  >  MySQL · Engine-Funktionen · Detaillierte Einführung in das InnoDB IO-Subsystem

MySQL · Engine-Funktionen · Detaillierte Einführung in das InnoDB IO-Subsystem

黄舟
黄舟Original
2017-03-04 14:29:381198Durchsuche

Vorwort

Als ausgereifte plattformübergreifende Datenbank-Engine implementiert InnoDB eine Reihe effizienter und benutzerfreundlicher E/A-Schnittstellen, einschließlich synchroner asynchroner E/A, E/A-Zusammenführung usw. In diesem Artikel wird kurz die interne Implementierung vorgestellt. Der Hauptcode ist in der Datei os0file.cc konzentriert. Die Analyse in diesem Artikel basiert standardmäßig auf MySQL 5.6, CentOS 6 und gcc 4.8. Auf Informationen zu anderen Versionen wird gesondert hingewiesen.

Grundkenntnisse

WAL-Technologie: Log-First-Technologie, grundsätzlich verwenden alle Datenbanken diese Technologie. Vereinfacht ausgedrückt: Wenn ein Datenblock geschrieben werden muss, schreibt der Datenbank-Front-End-Thread zuerst das entsprechende Protokoll (batch-sequentielles Schreiben) auf die Festplatte und teilt dem Client dann mit, dass der Vorgang erfolgreich ist des Datenblocks (diskretes zufälliges Schreiben) Legen Sie ihn dann in den Hintergrund-E/A-Thread. Bei Verwendung dieser Technologie ist zwar ein weiterer Schreibvorgang auf die Festplatte erforderlich, da das Protokoll jedoch nacheinander in Stapeln geschrieben wird. Sie ist jedoch sehr effizient, sodass der Client die Antwort schnell erhalten kann. Wenn die Datenbank außerdem abstürzt, bevor die eigentlichen Datenblöcke auf die Festplatte geschrieben wurden, kann die Datenbank das Protokoll zur Wiederherstellung nach einem Absturz verwenden, ohne dass es beim Neustart zu Datenverlusten kommt.
Daten vorlesen: Die Datenblöcke B und C „angrenzend“ an Datenblock A weisen beim Lesen von A ebenfalls einen großen Unterschied auf Beim Lesen von B können sie im Voraus in den Speicher eingelesen werden. Dies ist die Datenvorlesetechnologie. Die hier erwähnte Adjazenz hat zwei Bedeutungen: eine ist physische Adjazenz und die andere ist logische Adjazenz. Nachbarschaften in der zugrunde liegenden Datendatei werden als physisch benachbart bezeichnet. Wenn die Datendateien nicht benachbart, sondern logisch benachbart sind (die Daten mit der ID = 1 und die Daten mit der ID = 2 sind logisch benachbart, aber nicht unbedingt physisch benachbart und können an verschiedenen Stellen in derselben Datei vorhanden sein), ist dies der Fall sogenannte logische Adjazenz.
Dateiöffnungsmodus: Es gibt drei allgemeine Hauptmodi für Open-System-Aufrufe: O_DIRECT, O_SYNC und Standardmodus. Der O_DIRECT-Modus bedeutet, dass nachfolgende Vorgänge an der Datei nicht den Dateisystem-Cache verwenden und den Cache des Kernels umgehen. Aus einer anderen Perspektive wird der O_DIRECT-Modus zum Schreiben der Datei verwendet Wenn die Daten erfolgreich sind, werden sie tatsächlich auf die Festplatte geschrieben (unabhängig vom Cache der Festplatte) und der O_DIRECT-Modus wird zum Lesen der Datei verwendet. Jeder Lesevorgang wird tatsächlich von der Festplatte gelesen und nicht aus dem Cache das Dateisystem. O_SYNC bedeutet, dass der Betriebssystem-Cache verwendet wird und das Lesen und Schreiben von Dateien über den Kernel erfolgt. Dieser Modus garantiert jedoch auch, dass die Daten jedes Mal auf die Festplatte geschrieben werden. Der Standardmodus ähnelt dem O_SYNC-Modus, außer dass es keine Garantie dafür gibt, dass die Daten nach dem Schreiben noch auf die Festplatte geschrieben werden. Wenn der Host ausfällt, können die Daten verloren gehen.
Darüber hinaus erfordert der Schreibvorgang nicht nur das Schreiben der geänderten oder hinzugefügten Daten auf die Festplatte, sondern auch das Schreiben der Dateimetainformationen auf die Festplatte. Nur wenn beide Teile auf die Festplatte geschrieben werden, können Daten nicht verloren gehen. Der O_DIRECT-Modus garantiert nicht, dass Dateimetainformationen auf die Festplatte geschrieben werden (die meisten Dateisysteme tun dies jedoch, Fehler #45892). Wenn also keine anderen Vorgänge ausgeführt werden, besteht die Gefahr eines Verlusts nach dem Schreiben von Dateien mit O_DIRECT. O_SYNC stellt sicher, dass sowohl Daten als auch Metainformationen auf der Festplatte abgelegt werden. Keine der Daten ist im Standardmodus garantiert.
Nach dem Aufruf der Funktion fsync wird garantiert, dass die Daten und Protokolle auf die Festplatte geschrieben werden. Wenn Sie daher den O_DIRECT- und Standardmodus zum Öffnen der Datei verwenden, müssen Sie nach dem Schreiben der Daten die Funktion fsync aufrufen.
Synchronisierte E/A: Unsere häufig verwendete Lese-/Schreibfunktion (unter Linux) ist diese Art von E/A. Das Merkmal ist, dass der Aufrufer auf die Ausführung der Funktion wartet Die Funktion muss abgeschlossen werden, und es gibt keinen Nachrichtenbenachrichtigungsmechanismus, denn wenn die Funktion zurückkehrt, bedeutet dies, dass der Vorgang abgeschlossen ist, und Sie können feststellen, ob der Vorgang erfolgreich war, indem Sie später den Rückgabewert direkt überprüfen. Diese Art von E/A-Vorgang ist relativ einfach zu programmieren und kann alle Vorgänge im selben Thread abschließen, erfordert jedoch, dass der Aufrufer wartet. In einem Datenbanksystem ist es besser, ihn aufzurufen, wenn bestimmte Daten dringend benötigt werden WAL muss an den Client zurückgegeben werden. Vor dem Herunterladen wird ein synchroner E/A-Vorgang durchgeführt.
Asynchrone E/A: In der Datenbank verwendet der E/A-Thread, der Datenblöcke im Hintergrund leert, grundsätzlich asynchrone E/A. Der Front-End-Thread der Datenbank muss lediglich die Pinselblockanforderung an die asynchrone E/A-Warteschlange senden, bevor er zu anderen Aufgaben zurückkehrt, während der E/A-Thread des Hintergrundthreads regelmäßig prüft, ob diese übermittelten Anforderungen abgeschlossen wurden, und wenn ja, führt er einige Folgevorgänge durch. Verarbeitung. Gleichzeitig werden asynchrone E/A häufig in Stapeln von Anforderungen übermittelt. Wenn verschiedene Anforderungen auf dieselbe Datei zugreifen und aufeinanderfolgende Offsets aufweisen, können sie zu einer E/A-Anfrage zusammengeführt werden. Beispielsweise liest die erste Anfrage Datei 1, 200 Byte Daten, beginnend bei Offset 100, und die zweite Anfrage liest Datei 1, 100 Byte Daten, beginnend bei Offset 300, dann können die beiden Anfragen zu Datei 1, 300 Byte lesen, zusammengeführt werden der Daten ab Offset 100. Beim logischen Vorlesen beim Datenvorlesen wird häufig auch die asynchrone E/A-Technologie verwendet.
Die aktuelle asynchrone E/A-Bibliothek unter Linux erfordert, dass die Datei im O_DIRECT-Modus geöffnet wird und dass die Speicheradresse, an der der Datenblock gespeichert ist, der Offset beim Lesen und Schreiben der Datei sowie die Menge der gelesenen und geschriebenen Daten sein müssen Ganzzahliges Vielfaches der logischen Blockgröße des Dateisystems. Die logische Blockgröße des Dateisystems kann mit einer Anweisung ähnlich wie sudo blockdev --getss /dev/sda5 abgefragt werden. Wenn die oben genannten drei kein ganzzahliges Vielfaches der logischen Blockgröße des Dateisystems sind, wird beim Aufruf der Lese- und Schreibfunktionen ein EINVAL-Fehler gemeldet. Wenn die Datei jedoch nicht mit O_DIRECT geöffnet wird, kann das Programm trotzdem ausgeführt werden wird zu synchronem IO degradiert und blockiert den übergeordneten Funktionsaufruf io_submit.

InnoDB reguläre IO-Operationen und synchrone IO

Wenn das System in InnoDB über Preread/Pwrite-Funktionen (os_file_read_func und os_file_write_func) verfügt, verwenden Sie diese zum Lesen und Schreiben, andernfalls verwenden Sie lseek+read/ Schreibschema. Dies ist InnoDB synchrones IO. Wenn wir uns die preread/pwrite-Dokumentation ansehen, können wir sehen, dass diese beiden Funktionen den Offset des Dateihandles nicht ändern und threadsicher sind. Daher werden sie in Multithread-Umgebungen empfohlen. Die lseek+read/write-Lösung erfordert eine eigene Unter gleichzeitigen Bedingungen haben häufige Kernel-Statusfehler einen gewissen Einfluss auf die Leistung.

Verwenden Sie in InnoDB den Systemaufruf open, um die Datei zu öffnen (os_file_create_func) In Bezug auf den Modus zusätzlich zu O_RDONLY (schreibgeschützt), O_RDWR (Lesen/Schreiben) und O_CREAT (Datei erstellen). ), O_EXCL (garantiert: Es ist dieser Thread, der diese Datei erstellt hat) und O_TRUNC (Datei löschen). Standardmäßig (die Datenbank ist nicht auf den schreibgeschützten Modus eingestellt) werden alle Dateien im O_RDWR-Modus geöffnet. Der Parameter von innodb_flush_method ist wichtiger:

  • Wenn innodb_flush_method O_DSYNC festlegt, wird die Protokolldatei (ib_logfileXXX) mit O_SYNC geöffnet, sodass die Funktion nicht aufgerufen werden muss fsync, um die Festplatte nach dem Schreiben der Daten zu leeren. Die Datei (ibd) wird im Standardmodus geöffnet, daher muss fsync aufgerufen werden, um die Festplatte nach dem Schreiben der Daten zu leeren.

  • Wenn innodb_flush_method O_DIRECT festlegt, wird die Protokolldatei (ib_logfileXXX) im Standardmodus geöffnet. Nach dem Schreiben der Daten müssen Sie die Funktion fsync aufrufen, um die Datendatei zu leeren. ibd) wird im O_DIRECT-Modus geöffnet. Nach dem Schreiben müssen die Daten durch Aufrufen der fsync-Funktion geleert werden.

  • Wenn innodb_flush_method auf fsync eingestellt ist oder nicht, werden die Datendatei und die Protokolldatei im Standardmodus geöffnet und fsync ist erforderlich, um die Festplatte nach dem Schreiben der Daten zu leeren.

  • Wenn innodb_flush_method auf O_DIRECT_NO_FSYNC eingestellt ist, ähnelt die Dateiöffnungsmethode dem O_DIRECT-Modus. Der Unterschied besteht darin, dass nach dem Schreiben der Datendatei die fsync-Funktion nicht aufgerufen wird, um die Datei zu leeren Dies liegt hauptsächlich daran, dass O_DIRECT sicherstellen kann, dass die Metadaten auch auf der Festplatte im Dateisystem abgelegt werden.
    InnoDB unterstützt derzeit weder die Verwendung des O_DIRECT-Modus zum Öffnen von Protokolldateien noch die Verwendung des O_SYNC-Modus zum Öffnen von Datendateien.
    Beachten Sie, dass bei Verwendung des nativen Linux-AIO (Einzelheiten finden Sie im nächsten Abschnitt) die innodb_flush_method als O_DIRECT konfiguriert werden muss, andernfalls wird sie auf synchrone E/A heruntergestuft (im Fehlerprotokoll werden keine Aufgabenaufforderungen angezeigt).

InnoDB verwendet die Dateisperre des Dateisystems, um sicherzustellen, dass nur ein Prozess eine Datei liest und schreibt (os_file_lock), und verwendet die beratende Sperre (Advisory Locking) anstelle der obligatorischen Sperre (Obligatorisch). Sperren), da das obligatorische Sperren auf vielen Systemen, einschließlich Linux, Fehler aufweist. Im nicht schreibgeschützten Modus werden alle Dateien nach dem Öffnen mit Dateisperren gesperrt.

Verzeichnisse in InnoDB werden rekursiv erstellt (os_file_create_subdirs_if_needed und os_file_create_directory). Wenn Sie beispielsweise das Verzeichnis /a/b/c/ erstellen müssen, erstellen Sie zuerst c, dann b, dann a, erstellen Sie das Verzeichnis und rufen Sie die Funktion mkdir auf. Darüber hinaus erfordert das Erstellen der oberen Ebene des Verzeichnisses den Aufruf der Funktion os_file_create_simple_func anstelle von os_file_create_func.

InnoDB benötigt auch temporäre Dateien. Die Logik zum Erstellen temporärer Dateien ist relativ einfach (os_file_create_tmpfile). Verwenden Sie nach erfolgreicher Erstellung einer Datei im tmp-Verzeichnis direkt die Funktion zum Aufheben der Verknüpfung, um das Handle freizugeben. Wenn der Prozess endet (unabhängig davon, ob er normal oder abnormal endet), wird diese Datei automatisch freigegeben. Wenn InnoDB eine temporäre Datei erstellt, verwendet es zunächst die Logik der Serverschichtfunktion mysql_tmpfile. Da es später die Serverschichtfunktion aufrufen muss, um Ressourcen freizugeben, ruft es die Dup-Funktion auf, um ein Handle zu kopieren.

Wenn Sie die Größe einer Datei ermitteln müssen, überprüft InnoDB nicht die Metadaten der Datei (Funktion stat), sondern verwendet die Methode lseek(file, 0, SEEK_END), um die Dateigröße zu ermitteln dient dazu, Metadaten zu verhindern. Verzögerungen bei der Informationsaktualisierung führten dazu, dass eine falsche Dateigröße abgerufen wurde.

InnoDB weist allen neu erstellten Dateien (einschließlich Daten- und Protokolldateien) eine Größe zu. Der Inhalt der vorab zugewiesenen Dateien wird auf Null gesetzt (os_file_set_size). voll, es wird erweitert. Darüber hinaus wird beim Erstellen der Protokolldatei, also während der install_db-Phase, der Zuweisungsfortschritt im Fehlerprotokoll in 100-MB-Intervallen ausgegeben.

Im Allgemeinen sind herkömmliche E/A-Operationen und synchrone E/A relativ einfach, aber in InnoDB wird asynchrone E/A grundsätzlich zum Schreiben von Datendateien verwendet.

InnoDB asynchrone E/A

Da MySQL vor der nativen Linux-AIO geboren wurde, gibt es zwei Lösungen, um asynchrone E/A im asynchronen MySQL-E/A-Code zu implementieren.
Das erste ist das ursprüngliche simulierte AIO, das einen AIO-Mechanismus simulierte, bevor Linux native Air importiert wurde und auf einigen Systemen, die Air nicht unterstützten. Wenn eine asynchrone Lese- und Schreibanforderung gesendet wird, wird sie einfach in eine Warteschlange gestellt und dann zurückgegeben, und das Programm kann andere Dinge tun. Im Hintergrund gibt es mehrere asynchrone E/A-Verarbeitungsthreads (gesteuert durch die beiden Parameter innobase_read_io_threads und innobase_write_io_threads), die kontinuierlich Anforderungen aus dieser Warteschlange herausnehmen und dann synchrone E/A verwenden, um die Lese- und Schreibanforderungen sowie die Arbeit nach dem Lesen und Schreiben abzuschließen vollendet.
Das andere ist Native Aio. Derzeit wird es unter Linux mit io_submit, io_getevents und anderen Funktionen abgeschlossen (glibc aio wird nicht verwendet, dies wird ebenfalls simuliert). Senden Sie Anfragen mit io_submit und warten Sie mit io_getevents auf Anfragen. Darüber hinaus verfügt die Windows-Plattform auch über ein eigenes entsprechendes AIO, das hier nicht vorgestellt wird. Wenn Sie den Window-Technologie-Stack verwenden, sollte die Datenbank SQLServer verwenden. Derzeit können andere Plattformen (außer Linux und Windows) nur Simulate aio verwenden.

Stellen Sie zunächst einige allgemeine Funktionen und Strukturen vor und stellen Sie dann Simulate alo und Native aio unter Linux im Detail vor.
Globale Arrays sind in os0file.cc vom Typ os_aio_array_t definiert. Diese Arrays sind die Warteschlangen, die von Simulate aio zum Zwischenspeichern von Lese- und Schreibanforderungen verwendet werden. Jedes Element des Arrays ist vom Typ os_aio_slot_t, der jede E/A aufzeichnet . Der Typ der Anfrage, der fd der Datei, der Offset, die Menge der zu lesenden Daten, der Zeitpunkt, zu dem die IO-Anfrage initiiert wurde, ob die IO-Anfrage abgeschlossen wurde usw. Darüber hinaus befindet sich die Struktur iocb im nativen Linux-IO auch in os_aio_slot_t. In der Array-Struktur os_aio_slot_t werden einige statistische Informationen aufgezeichnet, z. B. wie viele Datenelemente (os_aio_slot_t) verwendet wurden, ob es leer ist, ob es voll ist usw. Es gibt insgesamt 5 solcher globalen Arrays, die zum Speichern asynchroner Datendatei-Leseanforderungen (os_aio_read_array), asynchroner Datendatei-Schreibanforderungen (os_aio_write_array), asynchroner Protokolldatei-Schreibanforderungen (os_aio_log_array) und Einfügen verwendet werden Puffer für asynchrone Schreibvorgänge (os_aio_ibuf_array), Datendateisynchronisierungs-Lese- und Schreibanforderung (os_aio_sync_array). Das Schreiben des Datenblocks in die Protokolldatei erfolgt über synchrone E/A, aber warum müssen wir dem Protokollschreiben hier eine asynchrone Anforderungswarteschlange (os_aio_log_array) zuweisen? Der Grund dafür ist, dass die Checkpoint-Informationen im Protokollheader der InnoDB-Protokolldatei aufgezeichnet werden müssen. Derzeit wird das Lesen und Schreiben von Checkpoint-Informationen immer noch über asynchrone E/A implementiert, da dies nicht sehr dringend ist. Wenn auf der Windows-Plattform asynchrone E/A für eine bestimmte Datei verwendet wird, kann die Datei keine synchrone E/A verwenden. Daher wird die synchrone Lese- und Schreibanforderungswarteschlange für Datendateien (os_aio_sync_array) eingeführt. Die Protokolldatei muss nicht aus der asynchronen Anforderungswarteschlange gelesen werden, da das Protokoll nur während der Wiederherstellung nach einem Absturz gelesen werden muss und die Datenbank bei der Wiederherstellung nach einem Absturz noch nicht verfügbar ist, sodass nicht in den asynchronen Lesemodus gewechselt werden muss . Hierbei ist zu beachten, dass es unabhängig von den beiden Parametern der Variablen innobase_read_io_threads und innobase_write_io_threads nur ein os_aio_read_array und os_aio_write_array gibt, die os_aio_slot_t-Elemente in den Daten jedoch entsprechend zunehmen Die Variable erhöht sich um 1 und die Elementzahl erhöht sich um 256. Wenn beispielsweise innobase_read_io_threads = 4 ist, ist das Array os_aio_read_array in vier Teile unterteilt. Jeder Teil verfügt über 256 Elemente. Jeder Teil verfügt über eine eigene unabhängige Sperre, ein Semaphor und statistische Variablen, die zur Simulation von 4 Threads verwendet werden. Innobase_write_io_threads ist ähnlich. Hier können wir auch erkennen, dass es eine Obergrenze für die Lese- und Schreibanforderungen gibt, die jeder asynchrone Lese-/Schreibthread zwischenspeichern kann, nämlich 256. Wenn diese Zahl überschritten wird, müssen nachfolgende asynchrone Anforderungen warten. 256 kann als Kontrolle der InnoDB-Schicht über die Anzahl der asynchronen E/A-Parallelität verstanden werden, und es gibt auch Längenbeschränkungen auf Dateisystemebene und Festplattenebene, die mit cat /sys/block/sda/queue/nr_requests bzw. cat /sys/block/sdb/queue/nr_requests abgefragt werden können.
os_aio_init wird aufgerufen, wenn InnoDB gestartet wird, um verschiedene Strukturen zu initialisieren, einschließlich des oben genannten globalen Arrays sowie Sperren und Mutexe, die in Simulate aio verwendet werden. os_aio_free gibt die entsprechende Struktur frei. Die os_aio_print_XXX-Funktionsreihe dient zur Ausgabe des Status des AIO-Subsystems und wird hauptsächlich in der show engine innodb status-Anweisung verwendet.

Simulate aio

Im Vergleich zu Native aio ist Simulate aio relativ kompliziert, da InnoDB seine eigenen Simulationsmechanismen implementiert.

  • Die Eingabefunktion lautet os_aio_func. Im Debug-Modus werden Parameter überprüft, z. B. die Speicheradresse, an der der Datenblock gespeichert ist, der Offset des Dateilesens und -schreibens usw Ob die Daten gelesen und geschrieben werden, ist ein ganzzahliges Vielfaches von OS_FILE_LOG_BLOCK_SIZE, es wird jedoch nicht überprüft, ob O_DIRECT im Dateiöffnungsmodus verwendet wird, da Simulate aio letztendlich synchrone E/A verwendet und es nicht erforderlich ist, O_DIRECT zum Öffnen zu verwenden Datei.

  • Nachdem die Überprüfung bestanden wurde, wird os_aio_array_reserve_slot aufgerufen, um diese E/A-Anforderung einem bestimmten Hintergrund-IO-Verarbeitungsthread zuzuweisen (zugewiesen durch innobase_xxxx_io_threads, aber tatsächlich im selben globalen Array) und Zeichnen Sie die relevanten Informationen der IO-Anfrage auf, um die Verarbeitung des IO-Threads im Hintergrund zu erleichtern. Wenn der E/A-Anforderungstyp derselbe ist, dieselbe Datei angefordert wird und der Offset relativ nahe beieinander liegt (standardmäßig liegt der Offsetunterschied innerhalb von 1 MB), weist InnoDB die beiden Anforderungen demselben E/A-Thread zu, um nachfolgende Schritte mittlerer E/A zu erleichtern verschmelzen.

  • Nachdem Sie die E/A-Anfrage gesendet haben, müssen Sie den Hintergrund-IO-Verarbeitungsthread aktivieren, denn wenn der Hintergrundthread erkennt, dass keine E/A-Anfrage vorliegt, wechselt er in den Wartezustand (os_event_wait).

  • An diesem Punkt kehrt die Funktion zurück, das Programm kann andere Dinge tun und die nachfolgende E/A-Verarbeitung wird an den Hintergrundthread übergeben.
    Stellen Sie vor, wie der Hintergrund-E/A-Thread gehandhabt wird.

  • Wenn InnoDB startet, wird der Hintergrund-IO-Thread gestartet (io_handler_thread). Es ruft os_aio_simulated_handle auf, um die E/A-Anfrage aus dem globalen Array zu entnehmen und sie dann mit synchroner E/A zu verarbeiten. Anschließend muss die Arbeit abgeschlossen werden, wenn es sich beispielsweise um eine Schreibanforderung handelt muss aus der Dirty-Seite im Pufferpool entfernt werden. Aus der Liste entfernt.

  • os_aio_simulated_handleZuerst müssen Sie eine E/A-Anfrage aus dem Array auswählen, die ausgeführt werden soll. Der Auswahlalgorithmus ist kein einfaches First-In-First-Out. Er wählt die Anfrage aus Der kleinste Versatz aller zuerst zu verarbeitenden Anforderungen dient dazu, die Berechnung der nachfolgenden E/A-Zusammenführung zu erleichtern. Dies kann jedoch auch leicht dazu führen, dass einzelne Anfragen mit besonders großen Offsets längere Zeit nicht ausgeführt werden, also verhungern. Um dieses Problem zu lösen, führt InnoDB zunächst einen Durchlauf durch Eine Anfrage wurde vor 2 Sekunden gefunden. Wenn sie gepusht wurde (d. h. 2 Sekunden gewartet hat), aber noch nicht ausgeführt wurde, wird die älteste Anfrage zuerst ausgeführt, um zu verhindern, dass diese Anfragen ausgehungert werden Bei gleicher Wartezeit wird die Anfrage mit dem kleineren Offset ausgewählt.

  • os_aio_simulated_handleDer nächste Schritt besteht darin, die E/A-Zusammenführung durchzuführen. Leseanforderung 1 fordert beispielsweise Datei1 an, 200 Bytes beginnend mit Offset100, und Leseanforderung 2 fordert Datei1 an, beginnend mit 100 Bytes Ab Offset300 können diese beiden Anforderungen zu einer Anforderung zusammengeführt werden: Datei1, 300 Bytes ab Offset100. Kopieren Sie nach der Rückkehr von IO einfach die Daten in den Puffer der ursprünglichen Anforderung. Die Schreibanforderung ist ähnlich. Vor dem Schreibvorgang werden die zu schreibenden Daten in einen temporären Bereich kopiert und dann alle auf einmal geschrieben. Beachten Sie, dass E/A nur dann zusammengeführt werden, wenn die Offsets kontinuierlich sind. Wenn es Unterbrechungen oder Überlappungen gibt, werden sie nicht zusammengeführt. Identische E/A-Anforderungen werden nicht zusammengeführt, sodass dies als Optimierungspunkt angesehen werden kann.

  • os_aio_simulated_handleWenn festgestellt wird, dass jetzt keine E/A-Anfrage vorliegt, wechselt es in den Wartezustand und wartet darauf, geweckt zu werden

Zusammenfassend lässt sich sagen, dass ausgehende E/A-Anforderungen das Gegenteil von einem einzelnen Push sind, der in einen Hintergrundthread gelangt und verarbeitet wird. Wenn die Hintergrundthreadpriorität relativ hoch ist, ist der E/A-Zusammenführungseffekt möglicherweise gering Um dieses Problem zu lösen, bietet Simulate aio eine ähnliche Gruppenübermittlungsfunktion, d. Dabei gibt es jedoch immer noch ein kleines Problem. Wenn der Hintergrundthread relativ beschäftigt ist, wechselt er nicht in den Wartezustand, was bedeutet, dass die Anforderung verarbeitet wird, solange sie in die Warteschlange gelangt. Dieses Problem kann im nativen AIO unten gelöst werden.
Im Allgemeinen ist der von InnoDB implementierte Simulationsmechanismus relativ sicher und zuverlässig. Wenn die Plattform Native AIO nicht unterstützt, wird dieser Mechanismus zum Lesen und Schreiben von Datendateien verwendet.

Linux natives AIO

Wenn auf dem System die Libaio-Bibliothek installiert ist und innodb_use_native_aio=on in der Konfigurationsdatei festgelegt ist, wird Native AIO beim Start verwendet.

  • Die Eingabefunktion ist immer noch os_aio_func Im Debug-Modus werden die eingehenden Parameter weiterhin überprüft. Es wird auch nicht überprüft, ob die Datei im O_DIRECT-Modus geöffnet ist Etwas riskant. Wenn der Benutzer nicht weiß, dass das native Linux-AIO den O_DIRECT-Modus verwenden muss, um Dateien zu öffnen, um die Vorteile von AIO zu nutzen, wird die Leistung nicht den Erwartungen entsprechen. Es empfiehlt sich, hier nachzuschauen und etwaige Probleme im Fehlerprotokoll auszugeben.

  • Nachdem die Prüfung erfolgreich war, rufen Sie wie bei Simulated aio os_aio_array_reserve_slot auf, um die E/A-Anforderung dem Hintergrundthread zuzuweisen. Der Zuweisungsalgorithmus berücksichtigt auch die nachfolgende E/A-Zusammenführung, genau wie Simulated aio. Der Hauptunterschied besteht darin, dass die iocb-Struktur mit den Parametern der IO-Anfrage initialisiert werden muss. Neben der Initialisierung des IOCB müssen auch die relevanten Informationen der E/A-Anforderung im Slot des globalen Arrays aufgezeichnet werden, hauptsächlich zur Vereinfachung der Statistik in der Funktionsreihe os_aio_print_XXX.

  • Rufen Sie io_submit an, um die Anfrage einzureichen.

  • An diesem Punkt kehrt die Funktion zurück, das Programm kann andere Dinge tun und die nachfolgende E/A-Verarbeitung wird an den Hintergrundthread übergeben.
    Als nächstes folgt der Hintergrund-IO-Thread.

  • Ähnlich wie bei Simulate aio wird auch der Hintergrund-IO-Thread gestartet, wenn InnoDB startet. Wenn es sich um ein natives Linux-AIO handelt, wird diese Funktion os_aio_linux_handle später aufgerufen. Die Funktion dieser Funktion ähnelt os_aio_simulated_handle, die zugrunde liegende Implementierung ist jedoch relativ einfach. Sie ruft nur die Funktion io_getevents auf, um auf den Abschluss der E/A-Anfrage zu warten. Das Zeitlimit beträgt 0,5 Sekunden. Wenn also innerhalb von 0,5 Sekunden keine E/A-Anfrage abgeschlossen wird, kehrt die Funktion zurück und ruft weiterhin io_getevents auf, um zu warten. Natürlich wird vor dem Warten festgestellt, ob der Server geschlossen ist, und wenn ja, Ausfahrt.

Versuchen Sie beim Verteilen von IO-Threads, benachbarte IOs in einem Thread zusammenzufassen. Dies ähnelt Simulate aio, aber für nachfolgende IO-Zusammenführungsvorgänge implementiert Simulate aio es selbst, Native aio ist es Wird vom Kernel vervollständigt, daher ist der Code relativ einfach.
Ein weiterer Unterschied besteht darin, dass Simulate aio in den Wartezustand wechselt, wenn keine E/A-Anforderungen vorliegen, während Native aio alle 0,5 Sekunden aufwacht, einige Überprüfungen durchführt und dann weiter wartet. Wenn daher eine neue Anfrage eingeht, erfordert Simulated AIO, dass der Benutzerthread aktiviert wird, Native AIO jedoch nicht. Darüber hinaus muss Simulate aio auch aufwachen, wenn der Server heruntergefahren wird, Native aio jedoch nicht.

Es kann festgestellt werden, dass Native AIO ähnlich wie Simulate AIO ist. Anforderungen werden einzeln übermittelt und dann einzeln verarbeitet. Dies führt zu einem schlechten IO-Zusammenführungseffekt. Das Facebook-Team hat eine Optimierung für die native AIO-Gruppenübermittlung eingereicht: Zuerst die E/A-Anforderungen zwischenspeichern und dann die Funktion io_submit aufrufen, um alle vorherigen Anforderungen auf einmal zu senden (io_submit kann mehrere Anforderungen gleichzeitig senden), sodass der Kernel bequemer ist um eine IO-Optimierung durchzuführen. Wenn Simulate aio unter starkem Druck auf den E/A-Thread steht, schlägt die Optimierung der Gruppenübermittlung fehl, Native aio jedoch nicht. Beachten Sie, dass die Gruppenübermittlung optimiert ist und Sie nicht zu viele auf einmal übermitteln können. Wenn die Länge der AIO-Warteschlange überschritten wird, wird die Einleitung eines io_submit erzwungen.

Zusammenfassung

Dieser Artikel stellt detailliert die Implementierung des IO-Subsystems in InnoDB und die Punkte vor, die bei der Verwendung beachtet werden müssen. InnoDB-Protokolle verwenden synchrone E/A, Daten verwenden asynchrone E/A und die Schreibreihenfolge der asynchronen E/A ist nicht der First-In-First-Out-Modus. Diese Punkte müssen beachtet werden. Obwohl Simulate aio einen relativ großen Lernwert hat, wird in modernen Betriebssystemen die Verwendung von Native aio empfohlen.

Das Obige ist eine detaillierte Einführung in die MySQL-Engine-Funktionen und das InnoDB-IO-Subsystem. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn