Heim  >  Artikel  >  Datenbank  >  Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

青灯夜游
青灯夜游nach vorne
2022-01-26 10:38:023315Durchsuche

Dieser Artikel führt Sie zum Verständnis des Thread-Modells in Redis6 und stellt das Single-Thread-Modell und das Multi-Thread-Modell vor. Ich hoffe, dass er Ihnen hilfreich sein wird!

Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

1. Entwicklungsgeschichte von Redis

Wenn wir einfach sagen, dass Redis Single-Threaded oder Multi-Threaded ist, ist diese Antwort sicherlich nicht streng. Die von verschiedenen Versionen verwendeten Threading-Modelle sind unterschiedlich. [Verwandte Empfehlungen: Redis-Video-Tutorial]

Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

  • Version 3.x, die früheste Version, bei der es sich um Mundpropaganda handelt, ist Single-Threaded.

  • Version 4.x ist streng genommen kein Single-Thread, aber der Thread, der für die Verarbeitung von Client-Anfragen verantwortlich ist, ist Single-Thread, hat aber begonnen, einige Multi-Thread-Dinge (asynchrones Löschen) . <code>多线程的东西(异步删除)

  • 最新版本的6.0.x后, 告别了大家印象中的单线程,用一种全新的多线程来解决问题。

2. Redis单线程模型

2.1 单线程真实含义

主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6
但Redis的其他功能, 比如持久化、异步删除、集群数据同步等等,其实是由额外的线程执行的。  可以这么说,Redis工作线程是单线程的。但是,整个Redis来说,是多线程的

2.2 单线程性能快原因

Redis 3.x 单线程时代但是性能很快的主要原因

  • 基于内存操作:所有数据都存在内存中,因此所有的运算都是内存级别的
  • 数据结构简单:Redis的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是o(1)
  • 多路复用和费阻塞IO:使用IO多路复用功能监听多个socket连接客户端,这样就可以使用一个线程连接处理多个请求,减少线程切换带来的开销,同时避免IO阻塞操作
  • 避免上下文切换:因为是单线程模型,就可以避免不必要的上先文切换和多线程竞争,这样可以省去多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生

2.3 采用单线程原因

Redis 是基于内存操作的, 因此他的瓶颈可能是机器的内存或者网络带宽而并非 CPU ,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了,况且使用多线程比较麻烦。 但是在 Redis 4.0 中开始支持多线程了,例如后台删除等功能
简单来说,Redis  4.0 之前一直采用单线程的主要原因有以下三个: 

  • 使用单线程模型是 Redis 的开发和维护更简单,因为单线程模型方便开发和调试;多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。Redis通过AE事件模型以及IO多路复用等技术,处理性能非常高,因此没有必要使用多线程。单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等 “线程不安全” 的命令都可以无锁进行。 

  • 即使使用单线程模型也并发的处理多客户端的请求,主要使用的是多路复用和非阻塞 IO; 

  • 对于 Redis 系统来说, 主要的性能瓶颈是内存或者网络带宽而并非 CPU

Nach der neuesten Version 6.0. 2. Redis Single-Threaded-Modell Redis verarbeitet Kundenanfragen des Kunden, einschließlich Erfassung (Socket-Lesen), Parsen, Ausführung, Inhaltsrückgabe (Socket-Schreiben) usw., werden alle von einem sequentiellen und seriellen Hauptthread verarbeitet, dem sogenannten „einzelnen Thread“. ". Dies ist auch der Hauptprozess für Redis zur Bereitstellung externer Schlüsselwertspeicherdienste. Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6
Aber andere Funktionen von Redis, wie

Persistenz, asynchrones Löschen, Cluster-Datensynchronisierung usw., werden tatsächlich von zusätzlichen Threads ausgeführt.​ Man kann sagen, dass der Redis-Worker-Thread ein Single-Thread ist. Allerdings ist das gesamte Redis multi-threaded; Code>Leistung ist schnell:

    Basierend auf Speicheroperationen: Alle Daten werden im Speicher gespeichert, sodass alle Vorgänge auf Speicherebene erfolgen

    Einfache Datenstruktur: Die Datenstruktur von Redis ist speziell entwickelt und einfach Daten Die meiste Zeit ist die Komplexität der Struktursuche und -operation o(1)Multiplexen und Blockieren von IO: Verwenden Sie die IO-Multiplexing-Funktion, um mehrere Socket-Verbindungen zum Client zu überwachen. Auf diese Weise ein Thread Die Verbindung kann zum Verarbeiten mehrerer Anforderungen verwendet werden, wodurch der durch Thread-Wechsel verursachte Overhead reduziert und gleichzeitig E/A-Blockierungsvorgänge vermieden werden.

    Kontextwechsel vermeiden: Da es sich um ein Single-Thread-Modell handelt, können unnötiger Kontextwechsel und Multithreading vermieden werden. Wettbewerb, dies kann Zeit und Leistungsverbrauch sparen, die durch Multi-Thread-Switching verursacht werden, und ein einzelner Thread verursacht keine Deadlock-Probleme code>Der Speicher oder die Netzwerkbandbreite der Maschine und nicht die CPU Da die CPU nicht der Engpass ist, ist es natürlich, eine Single-Thread-Lösung zu verwenden, und die Verwendung von Multi-Threads ist problematischer. In Redis 4.0 begann es jedoch, Multithreading wie Hintergrundlöschung und andere Funktionen zu unterstützen.
    Um es einfach auszudrücken: Es gibt drei Hauptgründe, warum Single-Threading vor Redis 4.0 verwendet wurde: 🎜🎜🎜🎜Die Verwendung eines Single-Threaded-Modells vereinfacht die Entwicklung und Wartung von Redis, da das Single-Threaded-Modell verwendet wird ist praktisch für die Entwicklung und das Debuggen. Obwohl das Threading-Modell in einigen Aspekten eine gute Leistung erbringt, führt es zu Unsicherheiten in der Reihenfolge der Programmausführung, führt zu einer Reihe von Problemen beim gleichzeitigen Lesen und Schreiben, erhöht die Systemkomplexität und kann einen Thread-Wechsel erfordern oder sogar Sperren und Entsperren, Leistungsverlust durch Deadlock. Redis verfügt über eine sehr hohe Verarbeitungsleistung durch AE-Ereignismodell und IO-Multiplexing sowie andere Technologien, sodass kein Multithreading erforderlich ist. Der Single-Thread-Mechanismus reduziert die Komplexität der internen Implementierung von Hash erheblich. Rehash, Lpush und andere „Thread-unsichere“ Befehle können ohne Sperren ausgeführt werden. 🎜🎜🎜🎜Selbst bei Verwendung eines Single-Thread-Modells können mehrere Clientanforderungen gleichzeitig verarbeitet werden, hauptsächlich mithilfe von Multiplexing und nicht blockierendem E/A; 🎜🎜🎜🎜Für das Redis-System ist der Hauptleistungsengpass der Speicher oder die Netzwerkbandbreite anstelle der CPU . 🎜🎜🎜🎜🎜3. Redis Multi-Threading-Modell🎜🎜🎜🎜🎜3.1 Gründe für die Einführung von Multi-Threading🎜🎜🎜

    Da Single-Threading so gut ist, warum müssen wir Multi-Threading einführen? Ein einzelner Thread hat auch seine eigenen Probleme, wie zum Beispiel das 既然单线程那么好,为啥又要引入多线程?单线程也有自己的烦恼,比如大key删除问题: 正常情况下使用 del 指令可以很快的删除数据,而当被删除的 key 是一个非常大的对象时,例如时包含了成千上万个元素的 hash 集合时,那么 del 指令就会造成 Redis 主线程卡顿。

    因此,在 Redis 4.0 中就新增了多线程的模块,当然此版本中的多线程主要是为了解决删除数据效率比较低的问题。可以通过惰性删除有效避免Redis卡顿问题(大key删除等问题),步骤如下:

    • unlink key : 与DEL一样删除key功能的lazy free实现,唯一不同是,UNLINK在删除集合类型键时,如果集合键的元素个数大于64个,主线程中只是把待删除键从数据库字典中摘除,会把真正的内存释放操作,给单独的bio来操作。如果元素个数较少(少于64个)或者是String类型,也会在主线程中直接删除。

    • flushall/flushdb async : 对于清空数据库命令flushall/flushdb,添加了async异步清理选项,使得redis在清空数据库时都是异步操作。实现逻辑是为数据库新建一个新的空的字典,把原有旧的数据库字典给后台线程来逐一删除其中的数据,释放内存。

    • 把删除工作交给了后台子进程异步删除数据

    因为Redis是单个主线程处理,redis之父antirez一直强调"Lazy Redis is better Redis". 而lazy free的本质就是把某些cost(主要时间复制度,占用主线程cpu时间片)较高删除操作, 从redis主线程剥离让bio子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题。

    Redis 4.0 就引入了多个线程来实现数据的异步惰性删除等功能,但是其处理读写请求的仍然只有一个线程,所以仍然算是狭义上的单线程。

    从上一小结分析:Redis的主要性能瓶颈是内存或网络带宽而并非CPU。内存问题比较好解决,因此Redis的瓶颈原因为网络IO。接下来,引入多线程模型。

    3.2 多线程工作原理

    I/O 的读和写本身是堵塞的,比如当 socket 中有数据时,Redis 会通过调用先将数据从内核态空间拷贝到用户态空间,再交给 Redis 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

    在 Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6
    结合上图可知,将网络数据读写、请求协议解析通过多个IO线程的来处理,对于真正的命令执行来说,仍然使用主线程操作(线程安全),是个不错的折中办法。因此,对于整个Redis来说是多线程的,但是对于工作线程(命令执行)仍旧是单线程

    3.3 工作流程

    核心流程大概如下:Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6
    流程简述如下:

    • 主线程获取 socket 放入等待列表
    • 将 socket 分配给各个 IO 线程(并不会等列表满)
    • 主线程阻塞等待 IO 线程(多线程)读取 socket 完毕
    • 主线程执行命令 - 单线程(如果命令没有接收完毕,会等 IO 下次继续)
    • 主线程阻塞等待 IO 线程(多线程)Problem beim Löschen großer Schlüssel
    • : Unter normalen Umständen kann die Del-Anweisung zum schnellen Löschen von Daten verwendet werden. Wenn es sich bei dem gelöschten Schlüssel jedoch um ein sehr großes Objekt handelt, z. B. um einen Hash-Satz mit Tausenden von Elementen, führt die Del-Anweisung zum Ausfall des Redis-Masters steckt fest.
    • Daher wurde
    Redis 4.0 ein Multithreading-Modul hinzugefügt. Natürlich dient das Multithreading in dieser Version hauptsächlich dazu, das Problem der relativ geringen Datenlöscheffizienz zu lösen. Sie können Redis-Verzögerungsprobleme (Löschen großer Schlüssel usw.) durch

    Lazy Deletion effektiv vermeiden. Die Schritte sind wie folgt:

      🎜unlink key : Eine verzögerte, kostenlose Implementierung der Schlüssellöschfunktion wie DEL. Der einzige Unterschied besteht darin, dass der Hauptthread beim Löschen eines festgelegten Typschlüssels nur diesen entfernt, wenn die Anzahl der Elemente im festgelegten Schlüssel größer als 64 ist Schlüssel, der aus dem Datenbankwörterbuch gelöscht werden soll. Überlassen Sie den eigentlichen Speicherfreigabevorgang einer separaten Biografie. Wenn die Anzahl der Elemente gering ist (weniger als 64) oder vom Typ String, werden diese auch direkt im Hauptthread gelöscht. 🎜🎜🎜🎜flushall/flushdb async: Für den Befehl „flushall/flushdb“ zum Löschen der Datenbank wird die Option „asynchrone asynchrone Bereinigung“ hinzugefügt, sodass Redis beim Löschen der Datenbank asynchron arbeitet. Die Implementierungslogik besteht darin, ein neues leeres Wörterbuch für die Datenbank zu erstellen und das ursprüngliche alte Datenbankwörterbuch an den Hintergrundthread zu übergeben, um die Daten einzeln zu löschen und den Speicher freizugeben. 🎜🎜🎜🎜Die Löscharbeit wird an den untergeordneten Hintergrundprozess übergeben, um Daten asynchron zu löschen🎜🎜🎜🎜Da Redis von einem einzigen Hauptthread verarbeitet wird, hat Antirez, der Vater von Redis, immer betont: „Lazy Redis ist das bessere Redis.“ ". Und Lazy Free Die Essenz des Codes> besteht darin, bestimmte kostspielige (Hauptzeitreplikation, Belegung der CPU-Zeitscheibe des Hauptthreads) und hohe Löschvorgänge aus dem Redis-Hauptthread zu entfernen und den Bio-Sub zu lassen -thread verarbeitet es, was die Blockierungszeit des Hauptthreads erheblich verkürzt. Dies reduziert Leistungs- und Stabilitätsprobleme, die durch das Löschen verursacht werden. 🎜🎜Redis 4.0 führte mehrere Threads ein, um Funktionen wie das asynchrone verzögerte Löschen von Daten zu implementieren, verfügt jedoch immer noch nur über einen Thread zum Verarbeiten von Lese- und Schreibanforderungen, sodass es im engeren Sinne immer noch als einzelner Thread betrachtet wird. 🎜🎜 Analyse aus der vorherigen Zusammenfassung: Der Hauptleistungsengpass von Redis ist die Speicher- oder Netzwerkbandbreite und nicht die CPU. Das Speicherproblem ist relativ einfach zu lösen, daher ist der Engpass von Redis die Netzwerk-E/A. Als nächstes wird das Multithreading-Modell vorgestellt. 🎜🎜🎜3.2 Funktionsprinzip von Multithreading🎜🎜🎜E/A-Lesen und -Schreiben selbst wird blockiert, wenn sich beispielsweise Daten im Socket befinden , Redis wird die Daten zunächst durch den Aufruf aus dem Kernel-Bereich in den Benutzerbereich kopieren und dann für den Aufruf an Redis übergeben. Dieser Kopiervorgang ist blockierend, wenn die Datenmenge größer ist , und diese Vorgänge werden in einem einzelnen Thread abgeschlossen. Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6🎜🎜In Redis 6.0 wurde eine neue Multithreading-Funktion hinzugefügt, um die E/A-Lese- und Schreibleistung zu verbessern. Die Hauptidee der Implementierung besteht darin, die E/A-Lese- und Schreibaufgaben aufzuteilen Hauptthread Geben Sie eine Gruppe unabhängiger Threads zur Ausführung an, sodass das Lesen und Schreiben mehrerer Sockets parallelisiert werden kann. Durch die Verwendung der Mehrkanal-E/A-Multiplexing-Technologie kann ein einzelner Thread mehrere Verbindungsanforderungen effizient verarbeiten (Minimierung des Netzwerks). IO-Zeitverbrauch), das zeitaufwändigste Lesen von Sockets, das Parsen von Anforderungen und das Schreiben werden separat ausgelagert, und die verbleibende Befehlsausführung wird weiterhin seriell vom Hauptthread ausgeführt und interagiert mit den Daten im Speicher. Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6
      Wie aus der obigen Abbildung ersichtlich ist, liest und schreibt 🎜 Netzwerkdaten und analysiert Anforderungsprotokolle über mehrere E/A-Threads. Für die tatsächliche Befehlsausführung wird weiterhin die Haupt-Thread-Operation verwendet (. Thread-Sicherheit)🎜 ist ein guter Kompromiss. Daher ist multithreaded für das gesamte Redis, aber immer noch singlethreaded für den Arbeitsthread (Befehlsausführung). 🎜

      3.3 Arbeitsablauf

      🎜Der Kernprozess ist wie folgt: Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6Die aktuelle Obergrenze des Codelimits beträgt 512 und der Standardwert ist 1 (diese Funktion ausschalten))

    Nach Belastungstests durch Interessierte kann die aktuelle Leistungsfähigkeit um mehr als das 1-fache gesteigert werden.

    Frage 1: Die Warteliste ist nicht voll und wird nicht bearbeitet.
    Antwort: Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6Beim Blockieren wird erkannt, ob der IO-Thread noch Aufgaben hat. Warten Sie, bis die Verarbeitung abgeschlossen ist, bevor Sie fortfahren. Diese Aufgaben werden während der Ausführung hinzugefügt. Wenn die Anzahl der Aufgaben Ich habe immer noch Zweifel daran. Kann mir das jemand erklären (Kommentar)?

    3.4 Ist Multithreading standardmäßig aktiviert?

    In Redis6.0 ist Der Multithreading-Mechanismus standardmäßig deaktiviert. Wenn Sie die Multithreading-Funktion verwenden müssen, müssen Sie zwei Einstellungen in redis.conf vornehmen. Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6多线程机制默认是关闭的 ,如果需要使用多线程功能,需要在redis.conf中完成两个设置。Eine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6

    • 设置io-thread-do-reads配置项为yes,表示启动多线程。
    • 设置线程个数。关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3, 如果为 8 核 CPU 建议线程数设置为 6 ,线程数一定要小于机器核数,线程数并不是越大越好。

    4. 总结

    Redis自身出道就是优秀,基于内存操作、数据结构简单、多路复用和非阻塞 I/O、避免了不必要的线程上下文切换等特性,在单线程的环境下依然很快;

    但对于大数据的 key 删除还是卡顿厉害,因此在 Redis 4.0 引入了多线程unlink key/flushall async 等命令,主要用于 Redis 数据的异步删除;

    而在 Redis 6.0 中引入了 I/O 多线程的读写,这样就可以更加高效的处理更多的任务了, Redis 只是将 I/O 读写变成了多线程 ,而 命令的执行依旧是由主线程串行执行的 ,因此在多线程下操作 Redis 不会出现线程安全的问题

    Setzen Sie das Konfigurationselement io-thread-do-reads auf „Ja“, was bedeutet, dass mehrere Threads gestartet werden. Legen Sie die Anzahl der Threads fest. In Bezug auf die Einstellung der Anzahl der Threads lautet die offizielle Empfehlung: Wenn es sich um eine 4-Kern-CPU handelt, wird empfohlen, die Anzahl der Threads auf 2 oder 3 festzulegen. Wenn es sich um eine 8-Kern-CPU handelt, Es wird empfohlen, die Anzahl der Threads auf 6 festzulegen. Die Anzahl der Threads muss geringer sein als die Anzahl der Maschinenkerne. Die Anzahl der Threads ist nicht immer besser.

    4. Zusammenfassung

    Redis selbst ist seit seinem Debüt hervorragend, basierend auf Speicheroperationen, einfacher Datenstruktur, Multiplexing und nicht blockierender E/A, wodurch unnötiger Thread-Kontextwechsel und andere Funktionen vermieden werden. In einer Single-Thread-Umgebung ist es immer noch sehr schnell. 🎜🎜Aber das Löschen von Schlüsseln für große Datenmengen ist immer noch sehr langsam, daher wurden in Redis 4.0 Multithread-Befehle zum Aufheben der Verknüpfung von Key/Flushall und anderen Befehlen eingeführt, die hauptsächlich für die Asynchronität verwendet werden Löschen von Redis-Daten; 🎜🎜In Redis 6.0 wurde E/A-Multithread-Lesen und -Schreiben eingeführt, sodass mehr Aufgaben effizienter verarbeitet werden können. Redis wandelt E/A-Lesen und -Schreiben einfach in Multi-Threading um /code > und die Ausführung von Befehlen wird weiterhin seriell vom Hauptthread ausgeführt, sodass beim Betrieb von Redis unter Multithreads keine Thread-Sicherheitsprobleme auftreten. 🎜🎜🎜Redis Egal, ob es sich um das ursprüngliche Single-Thread-Design oder das aktuelle Multi-Thread-Design handelt, das dem ursprünglichen Design widerspricht, es gibt nur einen Zweck: Redis immer schneller zu machen. 🎜🎜🎜Weitere Kenntnisse zum Thema Programmierung finden Sie unter: 🎜Einführung in die Programmierung🎜! ! 🎜

    Das obige ist der detaillierte Inhalt vonEine kurze Analyse von Single-Thread- und Multi-Thread-Modellen in Redis6. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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