Redis ist Single-Threaded, aber warum ist es so schnell? Ein Grund dafür ist, dass Redis nicht blockierende E/A und Multiplexing verwendet, um eine große Anzahl von Clientverbindungen zu verarbeiten. Der folgende Artikel wird Ihnen helfen, das Thread-IO-Modell in Redis zu verstehen. Ich hoffe, er wird Ihnen hilfreich sein!
Redis ist eine Single-Threaded-Anwendung und Nginx sind beide Single-Threaded-Server. [Verwandte Empfehlungen: Redis-Video-Tutorial]
Der Grund, warum Redis Single-Threaded und so schnell ist:
Erstens, weil sich alle seine Daten im Speicher befinden und alle Vorgänge bei der Verwendung von Redis Vorgänge auf Speicherebene sind Achten Sie auf Anweisungen mit einer Zeitkomplexität von O(n). Wenn die Datenmenge zu groß ist, werden andere Anweisungen blockiert und gewartet.
Der zweite Grund ist, dass Redis nicht verwendet wird. Das Blockieren von E/A und Multiplexing verarbeitet eine große Anzahl von Clientverbindungen.
Wenn wir die Lese- und Schreibmethode des Sockets verwenden, blockiert sie standardmäßig.
Das heißt, die Lesemethode wird aufgerufen, um einen Parameter n zu übergeben, was bedeutet, dass sie nach dem Lesen zurückkehrt Bis zu n Bytes. Wenn kein Byte vorhanden ist, wartet der Thread weiterhin, bis Daten eingehen oder die Verbindung geschlossen wird, und der Thread kann die folgende Logik ausführen Blockiert im Allgemeinen nicht, es sei denn, der Kernel ist ein Socket. Wenn der zugewiesene Schreibpuffer voll ist, blockiert die Schreibmethode, bis im Puffer freier Speicherplatz vorhanden ist.
Das Bild unten zeigt den detaillierten Vorgang des Lesens und Schreibens von Sockets.
Non-blocking IO bietet bei der Verwendung von Sockets die Option Non_Blocking. Wenn diese Option aktiviert ist, blockieren die Lese- und Schreibmethoden nicht, können aber so viel lesen, wie sie können,
Wie viel Sie lesen können, hängt von der Anzahl der vom Kernel für den Socket zugewiesenen Datenbytes ab. Wie viel Sie schreiben können, hängt von der Anzahl der vom Kernel im Schreibpuffer des Sockets zugewiesenen Datenbytes ab
Die Lese- und Schreibmethoden geben Ihnen über den Rückgabewert Auskunft über die Anzahl der vom Programm gelesenen und geschriebenen Bytes. Nicht blockierendes E/A bedeutet, dass der Thread beim Lesen und Schreiben nicht mehr blockiert werden muss. Das Lesen und Schreiben kann sofort abgeschlossen werden und der Thread kann weiterhin andere Aufgaben ausführen. Multiplexing (Ereignisabfrage)Obwohl nicht blockierendes IO schnell ist, bringt es auch ein Problem mit sich. Der Thread liest die Daten und kehrt nach dem Lesen eines Teils davon zurück. Wann wird er mit dem Lesen fortfahren? verbleibende Daten? Beim Schreiben von Daten ist der Puffer voll und wurde nicht vollständig geschrieben. Wann werden die restlichen Daten weitergeschrieben? Wenn Sie weiterhin lesen oder schreiben können, sollten Sie der Anwendung eine Benachrichtigung geben, um der Anwendung mitzuteilen, dass Sie weiterhin lesen oder schreiben können. Zur Behebung dieses Problems wird die Ereignisabfrage-API verwendet. selectDas Betriebssystem stellt dem Benutzerprogramm eine Auswahlfunktion zur Verfügung. Die Eingabe ist die Lese- und Schreibdeskriptorliste read_fds und write_fds, und die Ausgabe sind die entsprechenden Lese- und Schreibereignisse timeout Parameter, die maximale Zeit, die der Thread auf eine Zeitüberschreitung wartet, wenn ein Ereignis auftritt, und der Thread wird mit der Verarbeitung fortfahren. Wenn die Zeitüberschreitungszeit überschritten wird, kehrt die Methode ebenfalls zurück Wenn das Ereignis abgerufen wird, kann der Thread die entsprechenden Ereignisse einzeln verarbeiten. Nachdem das Ereignis verarbeitet wurde, ruft er weiterhin die Auswahl-API-Abfrage auf, sodass der Thread tatsächlich eine Endlosschleife ist. Er wählt und verarbeitet weiter und geht zurück und weiter. Diese Endlosschleife wird als Ereignisschleife bezeichnet, und eine Schleife ist ein Zyklus.
Ereignisschleifen-Pseudocode:
while True read_events, write_events = select(read_fds, write_fds, timeout) for event in read_events: handle_read(event.fd) for event in write_events: handle_write(event.fd) handle_others() # 做其他的逻辑处理,处理定时任务等等
Über die Select-Funktion können wir die Lese- und Schreibereignisse mehrerer Kanaldeskriptoren verarbeiten, sodass Systemfunktionsaufrufe wie Select als Multiplexing-APIs bezeichnet werden.
Moderne Multiplexing-APIs Das Betriebssystem verwendet nicht mehr den Select-Systemaufruf, sondern Epoll (Linux) und KQueue (FreeBSD, MacOSX). Die Leistung von Select wird sehr schlecht, wenn die Anzahl der Deskriptoren zunimmt. Es gibt geringfügige Unterschiede , aber sie können alle mit dem obigen Pseudocode verstanden werden. Wenn ein Ereignis im Deskriptor auftritt, wird das Deskriptorereignis in einer Schleife verarbeitet. Der Lesevorgang des Serversocket-Objekts bezieht sich auf den Aufruf von Accept, um die neue Verbindung vom Client zu akzeptieren Wenn eine Verbindung zustande kommt, wird dies auch durch das von select aufgerufene Leseereignis benachrichtigt.
Die NIO-Technologie in Java ist die Ereignisabfrage, und auch andere Sprachen verfügen über diese Technologie. BefehlswarteschlangeRedis ordnet jedem Client-Socket eine Befehlswarteschlange zu, und die vom Client gesendeten Befehle werden in der Reihenfolge „First In, First Out“ durch die Warteschlange verarbeitet. AntwortwarteschlangeIn ähnlicher Weise werden die von Redis zurückgegebenen Ergebnisse auch über eine jedem Client zugeordnete Warteschlange zurückgegeben. Wenn die Warteschlange leer ist, müssen vorerst keine Schreibereignisse abgerufen werden Der Client-Deskriptor wird von „Entfernen Sie ihn aus write_fds“ geändert und stellen Sie den Deskriptor dann in die Warteschlange, wenn Daten vorhanden sind. Dadurch kann vermieden werden, dass festgestellt wird, dass keine Daten zum Schreiben vorhanden sind, wenn der Select-Systemaufruf das Schreibereignis zurückgibt, was zu einer leeren Abfrage führt. nutzlose Abfragen und Verbrauch der Maschinen-CPU.Der Server muss nicht nur auf E/A-Ereignisse reagieren, sondern auch einige andere Dinge verarbeiten, z. B. die eigenen geplanten Aufgaben der Anwendung. Wenn der Thread beim Select-Aufruf blockiert und auf die Rückgabe von Select wartet, ist dies der Fall führt dazu, dass einige geplante Aufgaben ablaufen, aber nicht ausgeführt werden. In diesem Heap werden die am schnellsten auszuführenden Aufgaben an oberster Stelle aufgeführt aktualisiert die Aufgaben, die das Ende des Heaps erreicht haben. Nach Abschluss der Verarbeitung wird die Zeit aufgezeichnet, die für die Ausführung der Aufgabe im Heap erforderlich ist Zeit ist der Wert des Timeouts. Nach der Ausführung sind keine weiteren Aufgaben erforderlich. Redis kann höchstens so lange blockieren und nach Ablauf der Zeit die entsprechende Verarbeitung durchführen.
Die Ereignisverarbeitungsprinzipien von NodeJs und Nginx ähneln denen von Redis.
Weitere Kenntnisse zum Thema Programmierung finden Sie unter:
Programmiervideos! !
Das obige ist der detaillierte Inhalt vonIn diesem Artikel erfahren Sie schnell, wie Sie das Thread-IO-Modell in Redis verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!