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.
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.
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 Dateisystem-Dateisperren, um sicherzustellen, dass nur ein Prozess eine Datei liest und schreibt (os_file_lock
), und verwendet beratende Sperren (advisorische Sperren) anstelle von obligatorischen Sperren (obligatorische 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 bestimmten 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 Dadurch soll verhindert werden, dass Metadaten aufgrund einer Verzögerung bei der Informationsaktualisierung in einer falschen Dateigröße abgerufen wurden.
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.
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.
Zuerst stellen wir einige gängige Funktionen und Strukturen vor und stellen 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 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 kein Wechsel in den asynchronen Lesemodus erforderlich ist . 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. Beispiel: innobase_read_io_threads = 4, dann ist das Array os_aio_read_array in vier Teile unterteilt, jeder Teil hat 256 Elemente und jeder Teil verfügt über eine eigene unabhängige Sperre, Semaphore 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.
Im Vergleich zu Native aio ist Simulate aio relativ kompliziert, da InnoDB seine eigenen Simulationsmechanismen implementiert.
Die Eingabefunktion ist 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 Versatz relativ nahe beieinander liegt (standardmäßig liegt der Versatzunterschied innerhalb von 1 MB), weist InnoDB die beiden Anforderungen demselben E/A-Thread zu, um nachfolgende Schritte mittlerer E/A zu erleichtern verschmelzen.
Nach dem Absenden der E/A-Anfrage 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_handle
Zuerst 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_handle
Der 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_handle
Wenn 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-Anfragen das Gegenteil davon sind, dass jeder Push in einen Hintergrundthread gelangt und verarbeitet wird. Wenn die Priorität des Hintergrundthreads 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.
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.
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).