Heim  >  Artikel  >  Datenbank  >  Warum ist Redis mit Single-Thread so schnell?

Warum ist Redis mit Single-Thread so schnell?

PHPz
PHPznach vorne
2023-05-26 09:56:061449Durchsuche

    Warum verwendet Redis einen einzelnen Thread?

    Der Overhead von Multi-Threading

    Wenn es kein gutes Systemdesign gibt, führt die Verwendung von Multi-Threading normalerweise zu den rechts gezeigten Ergebnissen (beachten Sie die Ordinate). Wenn Sie die Anzahl der Threads zum ersten Mal erhöhen, erhöht sich die Systemdurchsatzrate. Wenn Sie die Anzahl der Threads weiter erhöhen, steigt die Systemdurchsatzrate langsam an oder nimmt sogar ab.

    Warum ist Redis mit Single-Thread so schnell?

    Der entscheidende Engpass ist: Es gibt in der Regel gemeinsam genutzte Ressourcen im System, auf die mehrere Threads gleichzeitig zugreifen. Um die Korrektheit der gemeinsam genutzten Ressourcen sicherzustellen, sind zusätzliche Mechanismen erforderlich, um die Thread-Sicherheit zu gewährleisten, wie z B. eine Verriegelung, die mit zusätzlichen Kosten verbunden ist.

    Nehmen Sie als Beispiel den am häufigsten verwendeten List-Typ. Angenommen, Redis verwendet ein Multi-Thread-Design und es gibt zwei Threads A und B, die LPUSHList bzw. /code>- und <code>LPUSH-Operationen, um bei jeder Ausführung das gleiche Ergebnis zu erzielen, d. h. [B-Thread entnimmt die von A-Thread eingegebenen Daten], diese beiden Prozesse müssen seriell ausgeführt werden. Dies ist das Problem der gleichzeitigen Zugriffskontrolle gemeinsam genutzter Ressourcen, mit dem das Multithread-Programmiermodell konfrontiert ist. List类型来举例吧,假设Redis采用多线程设计,有两个线程A和B分别对ListLPUSHLPUSH操作,为了使得每次执行都是相同的结果,即【B线程取出A线程放入的数据】就需要让这两个过程串行执行。这就是多线程编程模式面临的共享资源的并发访问控制问题。

    Warum ist Redis mit Single-Thread so schnell?

    并发访问控制一直是多线程开发中的一个难点问题:如果只是简单地采用一个互斥锁,就会出现即使增加了线程,大部分线程也在等待获取互斥锁,并行变串行,系统吞吐率并没有随着线程的增加而增加。

    同时加入并发访问控制后也会降低系统代码的可读性和可维护性,所以Redis干脆直接采用了单线程模式。

    Warum ist Redis mit Single-Thread so schnell??

    之所以使用单线程是Redis设计者多方面衡量的结果。

    • Redis的大部分操作在内存上完成

    • 采用了高效的数据结构,例如哈希表和跳表

    • 采用了多路复用机制,使其在网络IO操作中能并发处理大量的客户端请求,实现高吞吐率

    既然Redis使用单线程进行IO,如果线程被阻塞了就无法进行多路复用了,所以不难想象,Redis肯定还针对网络和IO操作的潜在阻塞点进行了设计。

    网络与IO操作的潜在阻塞点

    在网络通信里,服务器为了处理一个Get请求,需要监听客户端请求(bind/listen),和客户端建立连接(accept),从socket中读取请求(recv),解析客户端发送请求(parse),最后给客户端返回结果(send)。

    最基本的一种单线程实现是依次执行上面的操作。

    Warum ist Redis mit Single-Thread so schnell?

    上面标红的accept和recv操作都是潜在的阻塞点:

    • 当Redis监听到有连接请求,但却一直不能成功建立起连接时,就会阻塞在accept()函数这里,其他客户端此时也无法和Redis建立连接

    • 当Redis通过recv()从一个客户端读取数据时,如果数据一直没有到达,也会一直阻塞

    基于多路复用的高性能IO模型

    为了解决IO中的阻塞问题,Redis采用了Linux的IO多路复用机制,该机制允许内核中,同时存在多个监听套接字和已连接套接字(select/epoll)。

    内核会一直监听这些套接字上的连接或数据请求。Redis会处理到达的请求,从而实现了一个线程处理多个IO流的效果。

    Warum ist Redis mit Single-Thread so schnell?

    此时,Redis线程就不会阻塞在某一个特定的客户端请求处理上,所以它可以同时和多个客户端连接并处理请求。

    回调机制

    select/epoll一旦监测到FD上有请求到达时,就会触发相应的事件被放进一个队列里,Redis线程对该事件队列不断进行处理,所以就实现了基于事件的回调。

    例如,Redis会对Accept和Read事件注册acceptget回调函数。当Linux内核监听到有连接请求或读数据请求时,就会触发Accept事件和Read事件,此时,内核就会回调Redis相应的acceptget

    Warum verwendet Redis so schnell einen einzelnen Thread?

    Gleichzeitiger Zugriff Kontrolle Es war schon immer ein schwieriges Problem in der Multithread-Entwicklung: Wenn Sie einfach eine Mutex-Sperre verwenden, scheint es, dass die meisten Threads darauf warten, die Mutex-Sperre zu erhalten, selbst wenn Threads hinzugefügt werden, Parallelitätsänderungen an der Serialisierung und das System Die Durchsatzrate steigt nicht mit der Anzahl der Threads.

    Gleichzeitig verringert das Hinzufügen einer gleichzeitigen Zugriffskontrolle auch die Lesbarkeit und Wartbarkeit des Systemcodes, sodass Redis einfach den Single-Thread-Modus übernimmt. 🎜🎜Warum ist Redis mit Single Thread so schnell? 🎜🎜Der Grund für die Verwendung eines einzelnen Threads ist das Ergebnis mehrerer Überlegungen des Redis-Designers. 🎜
    • 🎜Die meisten Vorgänge von Redis werden im Speicher ausgeführt🎜
    • 🎜Unter Verwendung effizienter Datenstrukturen wie Hash-Tabellen und Skip-Tabellen🎜
    • 🎜Verwendet einen Multiplex-Mechanismus, sodass eine große Anzahl von Client-Anfragen gleichzeitig in Netzwerk-IO-Vorgängen verarbeitet und ein hoher Durchsatz erzielt werden kann🎜
    • 🎜🎜Da Redis einen einzelnen Thread für IO verwendet, wenn der Thread blockiert ist Multiplexing kann nicht durchgeführt werden, daher ist es nicht schwer vorstellbar, dass Redis auch für potenzielle Blockierungspunkte im Netzwerk- und IO-Betrieb ausgelegt sein muss. 🎜🎜Potenzielle Blockierungspunkte im Netzwerk- und E/A-Betrieb🎜🎜Um bei der Netzwerkkommunikation eine Get-Anfrage zu verarbeiten, muss der Server auf die Client-Anfrage hören (bind/listen) und eine Verbindung mit dieser herstellen den Client (accept), lesen Sie die Anfrage vom Socket (recv), analysieren Sie die vom Client gesendete Anfrage (parse) und schließlich Geben Sie das Ergebnis an den Client zurück (send). 🎜🎜Die grundlegendste Single-Thread-Implementierung besteht darin, die oben genannten Vorgänge nacheinander auszuführen. 🎜🎜Warum ist Redis bei Verwendung eines einzelnen Threads so schnell?🎜🎜rot markiert Die Vorgänge „accept“ und „rev“ sind potenzielle Blockierungspunkte: 🎜
      • 🎜Wenn Redis eine Verbindungsanforderung erkennt, die Verbindung jedoch nicht erfolgreich herstellen kann, wird es im accept( ) Funktion, andere Clients können zu diesem Zeitpunkt keine Verbindung mit Redis herstellen🎜
      • 🎜Wenn Redis recv() von einem Client übergibt Wenn das Ende Daten liest, wenn Wenn die Daten nicht angekommen sind, werden sie immer blockiert Listening-Sockets und verbundene Sockets müssen gleichzeitig im Kernel vorhanden sein (select/epoll). 🎜🎜Der Kernel wartet immer auf Verbindungen oder Datenanfragen auf diesen Sockets. Redis verarbeitet eingehende Anforderungen und erzielt so den Effekt, dass ein Thread mehrere E/A-Streams verarbeitet. 🎜🎜Warum ist Redis mit einem einzelnen Thread so schnell?🎜🎜An dieser Stelle Gleichzeitig blockiert der Redis-Thread die Verarbeitung einer bestimmten Client-Anforderung nicht, sodass er gleichzeitig eine Verbindung zu mehreren Clients herstellen und Anforderungen verarbeiten kann. 🎜🎜Rückrufmechanismus🎜🎜Sobald select/epoll erkennt, dass eine Anfrage auf FD eintrifft, löst es das entsprechende Ereignis aus und stellt es in eine Warteschlange, sodass ereignisbasierte Rückrufe implementiert werden. 🎜🎜Zum Beispiel registriert Redis die Rückruffunktionen accept und get für Accept- und Read-Ereignisse. Wenn der Linux-Kernel eine Verbindungsanforderung oder eine Datenleseanforderung überwacht, löst er das Accept-Ereignis und das Read-Ereignis aus. Zu diesem Zeitpunkt ruft der Kernel die entsprechenden accept und get auf. Code> der zu verarbeitenden Redis-Funktion. 🎜🎜Leistungsengpässe von Redis🎜🎜Nach der obigen Analyse weist Redis immer noch einige Leistungsengpässe auf, obwohl mehrere Clientanforderungen gleichzeitig über den Multiplexing-Mechanismus überwacht werden können. Dies ist auch eine Situation, die wir in unserer täglichen Programmierung vermeiden müssen . 🎜<h4>1. Zeitaufwändige Vorgänge</h4> <p>Wenn eine Anfrage in Redis lange dauert, wirkt sich dies auf die Leistung des gesamten Servers aus. Nachfolgende Anfragen müssen auf die Verarbeitung der vorherigen zeitaufwändigen Anfrage warten, bevor sie verarbeitet werden können. </p> <p>Dies muss beim Entwerfen von Geschäftsszenarien vermieden werden. Der <code>lazy-free-Mechanismus von Redis erfordert auch die zeitaufwändige Freigabe von Speicher in einem asynchronen Thread zur Ausführung.

        2. Szenario mit hoher Parallelität

        Wenn die Parallelität sehr groß ist, gibt es einen Leistungsengpass beim Lesen und Schreiben von Client-E/A-Daten mit einem einzelnen Thread. Obwohl der E/A-Multiplexmechanismus verwendet wird, kann er immer noch nur den Client lesen Daten sequentiell mit einem einzelnen Thread, der nicht die Vorteile mehrerer CPU-Kerne nutzen kann.

        Redis in 6.0 kann CPU-Multi-Core und Multi-Threading zum Lesen und Schreiben von Client-Daten verwenden, aber nur das Lesen und Schreiben für den Client erfolgt parallel und die eigentliche Ausführung jedes Befehls erfolgt weiterhin Single-Threaded.

        Weitere interessante Fragen zu Redis

        Ich möchte diese Gelegenheit nutzen, um einige interessante Fragen zu Redis zu stellen.

        Warum ist Redis mit Single-Thread so schnell?

        • Warum Redis verwenden, ist es nicht schlecht, direkt auf den Speicher zuzugreifen?

        Tatsächlich ist dieser Artikel nicht klar definiert. Für einige Daten, die sich nicht häufig ändern, kann er nicht direkt im Speicher abgelegt werden. Beim Aktualisieren von Daten kann es zu Konsistenzproblemen kommen, d. h. die Daten werden möglicherweise nur auf einem Server geändert, sodass die Daten nur im lokalen Speicher vorhanden sind. Durch den Zugriff auf den Redis-Server kann das Konsistenzproblem mithilfe von Redis gelöst werden.

        • Was soll ich tun, wenn zu viele Daten vorhanden sind, die nicht im Speicher gespeichert werden können? Was soll ich beispielsweise tun, wenn ich 100 GB Daten zwischenspeichern möchte?

        Hier gibt es auch eine Werbung für das verteilte Open-Source-KV-Cache-System von Taobao. Theoretisch ist das Gesamtdatenvolumen unbegrenzt und es wurde auch auf Verfügbarkeit, Skalierbarkeit und Zuverlässigkeit optimiert . Upgrade, interessierte Freunde können es herausfinden~

    Das obige ist der detaillierte Inhalt vonWarum ist Redis mit Single-Thread so schnell?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen