Maison  >  Article  >  base de données  >  Pourquoi Redis est-il si rapide en utilisant un seul thread ?

Pourquoi Redis est-il si rapide en utilisant un seul thread ?

PHPz
PHPzavant
2023-05-26 09:56:061450parcourir

    Pourquoi Redis utilise-t-il un seul thread ?

    La surcharge du multi-threading

    S'il n'y a pas de bonne conception du système, l'utilisation du multi-threading conduira généralement aux résultats affichés à droite (notez l'ordonnée ). Lorsque vous augmentez pour la première fois le nombre de threads, le débit du système augmente. Lorsque vous augmentez encore le nombre de threads, le débit du système augmente lentement, voire diminue.

    Pourquoi Redis est-il si rapide en utilisant un seul thread ?

    Le principal goulot d'étranglement est le suivant : il existe généralement des ressources partagées auxquelles plusieurs threads accèdent en même temps dans le système afin de garantir l'exactitude. des ressources partagées, il est nécessaire de disposer de mécanismes supplémentaires pour garantir la sécurité des threads, tels que le verrouillage, qui entraîneront une surcharge supplémentaire.

    Prenons l'exemple du type List le plus couramment utilisé. Supposons que Redis adopte une conception multithread et qu'il existe deux threads A et B qui gèrent List. respectivement pour effectuer les opérations LPUSH et LPUSH, afin d'obtenir le même résultat à chaque fois, c'est-à-dire que [le thread B retire les données mises par A. thread], ces deux processus doivent être exécutés en série. Il s’agit du problème de contrôle d’accès simultané aux ressources partagées auquel est confronté le modèle de programmation multithread. List类型来举例吧,假设Redis采用多线程设计,有两个线程A和B分别对ListLPUSHLPUSH操作,为了使得每次执行都是相同的结果,即【B线程取出A线程放入的数据】就需要让这两个过程串行执行。这就是多线程编程模式面临的共享资源的并发访问控制问题。

    Pourquoi Redis est-il si rapide en utilisant un seul thread ?

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

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

    Pourquoi Redis est-il si rapide en utilisant un seul thread ??

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

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

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

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

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

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

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

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

    Pourquoi Redis est-il si rapide en utilisant un seul thread ?

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

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

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

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

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

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

    Pourquoi Redis est-il si rapide en utilisant un seul thread ?

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

    回调机制

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

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

    Pourquoi Redis est-il si rapide en utilisant un seul thread

    Le contrôle d'accès simultané a toujours été un problème difficile dans le développement multithread : si vous utilisez simplement un verrou mutex, il apparaîtra que même si des threads sont ajoutés, la plupart des threads attendent d'acquérir le mutex. Lock, modifications parallèles en série et le débit du système n'augmente pas avec l'augmentation du nombre de threads.

    Dans le même temps, l'ajout d'un contrôle d'accès simultané réduira également la lisibilité et la maintenabilité du code système, donc Redis adopte simplement le mode monothread. #🎜🎜##🎜🎜#Pourquoi Redis est-il si rapide en utilisant un seul thread ? #🎜🎜##🎜🎜#La raison pour laquelle un seul thread est utilisé est le résultat de nombreux aspects de l'évaluation des concepteurs Redis. #🎜🎜#
    • #🎜🎜#La plupart des opérations de Redis sont effectuées en mémoire #🎜🎜#
    • #🎜🎜# adopte des structures de données efficaces , tels que les tables de hachage et les tables de saut #🎜🎜#
    • #🎜🎜# adoptent un mécanisme de multiplexage pour lui permettre de gérer simultanément un grand nombre de requêtes client dans les opérations d'E/S réseau. #
    • #🎜🎜##🎜🎜#Étant donné que Redis utilise un seul thread pour les E/S, si le thread est bloqué, le multiplexage ne peut pas être effectué, il n'est donc pas difficile d'imaginer que Redis doit toujours être conçu pour des points d'étranglement potentiels dans les opérations réseau et IO. #🎜🎜##🎜🎜#Points de blocage potentiels des opérations réseau et IO#🎜🎜##🎜🎜#Dans la communication réseau, afin de traiter une requête Get, le serveur doit écouter la requête du client (bind /listen code>), établir une connexion avec le client (<code>accept), lire la requête depuis le socket (recv) et analyser la requête envoyée par le client (parse >), et renvoie enfin le résultat au client (send). #🎜🎜##🎜🎜#L'implémentation monothread la plus basique consiste à effectuer les opérations ci-dessus dans l'ordre. #🎜🎜##🎜🎜#Pourquoi Redis est-il si rapide en utilisant un seul thread#🎜🎜##🎜🎜#Les opérations d'acceptation et de réception marquées en rouge ci-dessus sont des points de blocage potentiels : #🎜🎜#
      • #🎜🎜#Quand Redis écoute Quand il y a une demande de connexion mais la connexion ne peut pas être établie avec succès, elle sera bloquée dans la fonction accept() et les autres clients ne pourront pas établir de connexion avec Redis pour le moment #🎜🎜 #
      • #🎜🎜#Lorsque Redis lit les données d'un client via recv(), si les données ne sont pas arrivées, il bloquera toujours #🎜🎜#
      • #🎜 🎜##🎜🎜#Modèle IO hautes performances basé sur le multiplexage#🎜🎜##🎜🎜#Afin de résoudre le problème de blocage dans IO, Redis adopte le mécanisme de multiplexage IO de Linux, qui permet au noyau d'avoir plusieurs prises d'écoute et prises connectées en même temps (select/epoll). #🎜🎜##🎜🎜#Le noyau écoutera toujours les connexions ou les demandes de données sur ces sockets. Redis traitera les requêtes entrantes, obtenant ainsi l'effet d'un thread traitant plusieurs flux d'E/S. #🎜🎜##🎜🎜#Pourquoi Redis est-il si rapide en utilisant un seul thread#🎜🎜##🎜🎜#Pour le moment, le thread Redis ne sera pas bloqué sur le traitement d'une demande client spécifique, il peut donc se connecter à plusieurs clients en même temps et traiter les demandes. #🎜🎜##🎜🎜#Mécanisme de rappel#🎜🎜##🎜🎜#select/epoll Une fois qu'une requête arrive sur le FD, l'événement correspondant sera déclenché et mis en file d'attente, et le thread Redis mettra l'événement en file d'attente. Traitement se poursuit, de sorte que les rappels basés sur les événements sont implémentés. #🎜🎜##🎜🎜#Par exemple, Redis enregistrera les fonctions de rappel accept et get pour les événements Accept et Read. Lorsque le noyau Linux surveille une demande de connexion ou une demande de lecture de données, il déclenchera l'événement Accept et l'événement Read. À ce moment, le noyau rappellera les accept et get correspondants. code> de la fonction Redis à traiter. #🎜🎜##🎜🎜#Les goulots d'étranglement des performances de Redis#🎜🎜##🎜🎜#Après l'analyse ci-dessus, bien que plusieurs demandes de clients puissent être surveillées en même temps via le mécanisme de multiplexage, Redis présente encore des goulots d'étranglement de performances , c'est aussi une situation que nous devons éviter dans notre programmation quotidienne. #🎜🎜#<h4>1. Opérations chronophages</h4> <p>Si une requête prend beaucoup de temps dans Redis, cela aura un impact sur les performances de l'ensemble du serveur. Les demandes suivantes doivent attendre que la demande précédente, qui prend beaucoup de temps, soit traitée avant de pouvoir être traitées. </p> <p>Cela doit être évité lors de la conception de scénarios commerciaux ; le mécanisme <code>lazy-free de Redis place également l'opération fastidieuse de libération de mémoire dans un thread asynchrone pour l'exécution.

        2. Scénario de concurrence élevée

        Lorsque le degré de concurrence est très important, il existe un goulot d'étranglement dans les performances de lecture et d'écriture des données d'E/S client avec un seul thread. Bien que le mécanisme de multiplexage d'E/S soit utilisé, il ne peut toujours lire que le client. données séquentiellement avec un seul thread et ne peut pas tirer parti de plusieurs cœurs de processeur.

        Redis dans 6.0 peut utiliser le processeur multicœur et multithread pour lire et écrire les données client, mais seules la lecture et l'écriture pour le client sont parallèles et le fonctionnement réel de chaque commande est toujours monothread.

        Autres questions intéressantes liées à Redis

        J'aimerais profiter de cette occasion pour poser quelques questions intéressantes liées à Redis.

        Pourquoi Redis est-il si rapide en utilisant un seul thread ?

        • Pourquoi utiliser Redis N'est-ce pas mauvais d'accéder directement à la mémoire ?

        En fait, cet article n'est pas clairement défini. Pour certaines données qui ne changent pas fréquemment, elles peuvent être placées directement dans la mémoire. Il peut y avoir des problèmes de cohérence lors de la mise à jour des données, c'est-à-dire que les données d'un seul serveur peuvent être modifiées, de sorte que les données n'existent que dans la mémoire locale. L'accès au serveur Redis peut résoudre le problème de cohérence, en utilisant Redis.

        • Que dois-je faire s'il y a trop de données qui ne peuvent pas être stockées dans la mémoire ? Par exemple, si je souhaite mettre en cache 100 Go de données, que dois-je faire ?

        Il y a aussi une publicité ici. Tair est le système de cache KV distribué open source de Taobao. Il hérite des opérations riches de Redis. Théoriquement, le volume total de données est illimité. Mettez à niveau, les amis intéressés peuvent le découvrir ~

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer