Redis单线程 VS 多线程

一、Redis 为什么选择单线程?

这种说法其实并不严谨,为什么这么说呢?

Redis的版本有很多 3.x4.x6.x,版本不同架构也不同的,不限定版本问是否单线程也是不太严谨。

版本3.x,最早版本,也就是大家口口相传的redis的单线程,在3.x的版本是redis确实是单线程。

版本4.x,严格意义上来说也不是单线程,而是负责处理客户端请求的线程是单线程,但是开始加了多线程的东西(异步删除)。--并没有完全显现。

2020年5月版本的6.0x后及2022年推出的7.0版本后,告别了大家印象中的单线程,用一种全新的多线程来解决问题。---已经完全体现了。

里程碑的重要版本

5.0版本是直接升级到6.0版本,对于这次激进的升级,redis之父antirez表示得很有信心和兴奋,所以第一时间发文阐述了6.0的一些重大功能"Redis 6.0.0 GA is out!" ,当然,Redis7.0后版本更加厉害

1.Redis单线程介绍

        主要是指Redis网络IO的键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取(socket 读)、解析执行内容返回(socket 写)等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是 Redis对外提供键值存储服务的主要流程。

但是Redis的其他功能,比如持久化RDB、AOF、异步删除、集群数据同步等,其实是由额外的线程执行

Redis命令工作线程是单线程的,但是,整个Redis来说是多线程的。

2.单线程为什么很快?

Redis 3.x单线程时代性能依旧很快的主要原因如下:

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

官方说明

https://redis.io/docs/get-started/faq/

Redis是单线程的,如何利用多个CPU/内核?

CPU并不是使用Redis的瓶颈,因为通常Redis要么受内存限制,例如,使用在平均Linux系统上运行的流水线Redis每秒可以发送一百万个请求,因此,如果应用主要使用 O(N) 或者 (log (N) ) 命令,则几乎不会使用过多的CPU。

但是,为了最大成都利用CPU,可以在同一框中启动多个Redis实例,并将它们视为不同的服务器,在某个时候,单核可能还是不够,因此,如果需要使用多个CPU,则可以开始考虑更早地进行分片的某种方法。

但是,在Redis 4.0中,Redis具有更多线程,目前,这个仅限于后台删除对象,以及阻止通过Redis模块实现的命令,对于将来的版本,计划使用Redis越来越线程化。

        大致意思就是说Redis是基于内存操作的,因此它的瓶颈可能是机器的内存或者网络带宽而不是CPU,既然CPU不是瓶颈,那么自然就采用单线程的解决方案了,况且使用多线程比较麻烦。但是在 Redis 4.0 中开始支持多线程了,例如后台删除、备份等功能

Redis 4.0 之前一直采用单线程的主要原因有以下三个 :

  1. 使用单线程模型是Redis的开发和维护更加简单,因为单线程模型方便开发和调试。
  2. 即使使用单线程模型也可以并发的处理多客户端的请求,主要使用的是IO多路复用和非阻塞IO;
  3. 对于Redis系统来说,主要的性能瓶颈是内存或者网络带宽而非CPU

3.Redis 为什么要加入多线程?

既然单线程这么好,为什么逐渐又要加入了多线程特性呢?

因为的单线程也存在一定的问题,如在执行复杂任务时,线程卡死等操作...

3.1 单线程的问题

        正常情况下使用del指令可以很快的删除数据,而当被删除的key是一个非常大的对象的时候,例如包含了成千上万的元素 hash 集合时,那么del指令就会造成 Redis主线程卡顿等问题。

        这就是 redis3.x单线程时代最经典的故障,大key删除的头疼的问题

        由于Redis是单线程的,del bigKey ...等待很久这个线程才会释放,类似加了一个synchronized锁,你可以详细高并发下,线程堵塞导致系统崩溃无法使用。

3.2 解决方法

        使用惰性删除可以有效的避免Redis卡顿的问题,因为在使用del key是同步操作,则可以使用异步的操作解决这个问题。

        比如当需要删除一个很大的数据时,因为是单线程原子命令操作,这就会导致Redis服务卡顿,于是在Redis4.0 中新增了多线程的模块,当然次版本中多线程主要是为了解决删除数据效率比较低的问。

unlink key

flushdb async

flushall async

包删除的工作交给后台的子线程来完成异步删除数据。

        因为Redis是单主线程处理,redis支付antirez一直强调"Lazy Redis is better Redis"。

        而lazy free的本质就是把某些cost(主要时间复制度,占用主线程cpu)较高删除操作,而redis主线程剥离让bio子线程来处理,极大地减少主线程阻塞时间。从而减少删除导致性能和稳定性问题。

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

二、Redis6/7的多线程特性和IO多路复用

        对于Redis主要的性能瓶颈是内存或者网络带宽而非CPU

1.网络瓶颈

在Redis6/7中,非常收关注的第一个新特性就是多线程

        这是因为,Redis一直被大家熟知的就是它的单线程架构,虽然有些命令操作可以用后台线程或者子线程执行(比如数据删除、快照生成、AOF重写)。但是,从网络IO处理到实际的读写命令处理,都是由单个线程完成的。

        随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络IO的处理上,也就是说,单个主线程处理网络请求的速度跟不上底层网络硬件的速度,为了应对这个问题:

        采用多个IO线程来处理网络请求,提高网络请求处理的并行度,Redis6/7就是采用的这种方法。

        但是,Redis的多IO线程只是用来处理网络请求的,对于读写操作命令Redis仍然使用单线程来处理。这是因为,Redis处理请求时,网络处理经常出现瓶颈,通过多个IO线程并行处理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为了保证Lua脚本事务的原子性、额外开发多线程互斥加锁机制了(不管加锁操作处理),这样一来,Redis线程模型实现就简单了。

2.主线程和IO线程协作

阶段一:服务端和客户端建立Socket连接,并分配处理线程

        首先,主线程负责接收建立连接请求,当有客户端请求和实例建立Socket连接时,主线程会创建和客户端的连接,并把Socket放入到全局等待队列中,紧接着,主线程通过轮询方式把Socket连接分配给IO线程。注意:主线程不一定会将连接直接分配给IO线程,而是通过 epoll或者其他I/O多路复用机制,主线程会监听多个连接,一旦有事件发生,比如有数据可读,主线程会通知对应的IO线程去处理,此外Redis可能会用线程来处理这些IO任务,而不是一对一地将连接分配给IO线程。

阶段二:IO线程读取并解析请求

        主线程一旦把Socket分配给IO线程,就会进入阻塞状态,等待IO线程完成客户端请求读取解析。因为有多个IO线程在并行处理,所以,这个过程很快就可以完成。

阶段三:主线程执行请求操作

        等待IO线程解析完请求,主线程还是会以单线程的方式执行这些命令操作。

阶段四:IO线程回写Socket和主线程清空全局队列

        当主线程执行完请求操作后,会把需要返回的结果写入到缓冲区,然后,主线程会阻塞等待IO线程,把这些结果写回到Socket中,并返回给客户端。和IO线程读取和解析请求一样,IO线程回写Socket时,也是有多个线程在并发执行,所以回写Socket的速度也很快。等到IO线程回写Socket完毕,主线程会清空全局队列,等待客户端的后续请求。

3.Unix网络中五种IO模型

  • Blocking IO - 阻塞IO
  • NoneBlocking IO - 非阻塞IO
  • IO multplexing - IO多路复用
  • signal driven IO - 信号驱动IO
  • asynchronous IO - 异步IO

IO multplexing - IO 多路复用

Linux世界中一切皆文件:文件描述符:简称FD,句柄

  File descriptor:文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引入的抽象化概念。文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,文件描述符这一概念往往只适用于UNIXLinux这样的操作系统。

4.IO多路复用

        一种同步的IO模型,实现一个线程监视多个文件句柄一旦某个文件句柄就绪就能够通知到对应应用程序进行响应的读写操作,没有文件句柄就绪时会阻塞应用程序,从而释放CPU资源。

        总而言之就是:I/O多路复用是一种高效的I/O操作机制,用于同时监视多个I/O流的可读性、可写性或异常情况,而无需为每个I/O流分配一个单独的线程或进程。这种技术允许一个单独的线程或进程来管理多个I/O操作,从而减少了系统资源的消耗并提高了系统的响应性和吞吐量。

4.1 概念

  • I/O:网络I/O,尤其在操作系统层面指数据在内核态和用户态之间的读写操作。
  • 多路多个客户端连接(连接就是套接字描述符,即socket 或者 channel)
  • 复用:复用一个或几个线程。
  • IO多路复用:也就是说一个或一组线程处理多个TCP连接,使用单进程就能够实现同时处理多个客户端的连接,无需创建或者维护过多的进程/线程。

一个服务端进程可以同时处理多个套接字描述符,实现IO多路复用的模型有三种:可以分select -> poll ->epoll三个阶段来描述。

select():select() 是一种比较早的I/O多路复用机制,它允许程序员监视一组文件描述符,并在其中任何一个文件描述符就绪时进行通知。但是select()有一些限制,比如它通常有最大文件描述符数量的限制,并且在大量文件描述符的情况下性能较差。

poll():poll() 是对select()的改进,它也可以同时监视多个文件描述符,但没有select()的一些限制,poll()使用一个pollfd结构数组来传递需要监视的文件描述符和所关注的事件。

epoll:epoll()是Linux特有的I/O多路复用机制,它提供了更高效的时间通知机制。相比较select()poll()epoll()在处理大量文件描述符时具有更好的性能。epoll()使用一个epoll实例来管理需要监视的文件描述符,并通过epoll_ctl()来添加、删除或者修改监视的文件描述符。然后通过epoll_wait()来等待就绪时间的发送。

I/O多路复用的优势在于,它避免了创建多个线程或者进程来处理I/O操作,从而减少了上下文切换的开销,提高了系统的性能和资源利用率,这种技术常用于网络编程中,用于处理大量并发连接的情况,例如WEB服务器、聊天服务器等。

4.2 IO多路复用模型

场景分析

        模拟一个tcp服务器处理30个客户端socket ,假设你是一个监考老师,让30个学生解答一道竞赛考题,然后负责验收学生答卷,你有下面几个选择:

        第一种选择(轮询):按照顺序逐个验收,先验收A、然后是B,之后是C、D。。。这中间如果有一个学生卡主了,全班都会被耽误,你用循环挨个处理socket,根本不具有并发能力。

        第二种选择(来一个new一个,一对一服务):你创建30个分身线程,每个分身线程检查一个学生的答案是否正确。这种类似于为每个用户创建一个进程或者线程处理连接。

        第三种选择(响应式处理,1对多服务):你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。这种就是IO复用模型Linux下的selectpollepoll就是干这个的。

IO多路复用模型

        将用户socket对应的文件描述符(FileDescriptor)注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。这样,整个过程只在调用selectpollepoll这些调用的时候才会堵塞,收发客户消息是不会阻塞的,整个进程或线程就被充分利用起来,这就是事件驱动,所谓的reactor反应模式。

        在单个线程通过记录跟踪每一个Socket(I/O流)的状态俩同时管理多个I/O流,一个服务端进程可以同时处理多个套接字描述符。目的是尽量的提高服务器的吞吐能力。

        大家都用过nignxnginx使用epoll接收请求,nginx会有很多请求过来,epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理。redis类似同理,这就是I/O多路复用原理,有请求就响应,没有请求不打扰。

4.3 Reactor模型

        Redis服务采用Reactor的方式来实现文件事件处理器(每一个网络连接其实都对应一个文件描述符)

        Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:

        多个套接字、IO多路复用程序、文件时间分配器、事件处理器,因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。

        基于I/O复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从线程阻塞状态返回,开始进行业务处理。

        Reactor模式,是指通过一个或者多个输入同时传递给服务器的服务请求的事件驱动处理模式。服务端程序处理传入多路请求,并将它们同步分派给请求对应处理线程,Reactor模式也叫Dispatcher模式,即I/O多路复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术。

Reactor模式中有2个关键组成:

  1. Reactor:Reactor在独立的线程中运行,负责监听和分发事件,分发给适当的处理程序对IO事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线程转移到适当的联系人;
  2. Handlers:处理程序执行I/O事件要完成的实际事件,类似于客户想要与之交谈的公司的实际办理人。Reactor通过调度适当的处理程序来响应I/O事件,处理程序执行非阻塞操作。

三、结论

  Redis工作线程是单线程的,但是对于整个Redis来说是多线程的。

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

        从Redis6开始,就新增了多线程的功能来提高I/O的读写性能,他的主要实现思路是将主线程的IO读写任务拆分给一组独立的线程去执行,这样就可以使多个socket的读写可以并行化了,采用多路I/O复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Scoket的读取、请求解析、写入单独外包出去,剩下的命令执行让然由主线程串行执行并和内存的数据交互。

结合上图可知,网络IO操作就变成多线程化了,其他核心部分仍然是线程安全的,是一个不错的折中办法。

  Redis6 --> 7将网络数据读写、请求协议解析通过多个IO线程来处理,对于真正的命令执行来说,仍然使用主线程操作,一举两得。

22

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/525069.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十二届蓝桥杯大赛软件赛省赛C/C++大学B组

第十二届蓝桥杯大赛软件赛省赛C/C 大学 B 组 文章目录 第十二届蓝桥杯大赛软件赛省赛C/C 大学 B 组1、空间2、卡片3、直线4、货物摆放5、路径6、时间显示7、砝码称重8、杨辉三角形9、双向排序10、括号序列 1、空间 1MB 1024KB 1KB 1024byte 1byte8bit // cout<<"2…

python基于opencv实现数籽粒

千粒重是一个重要的农艺性状&#xff0c;通过对其的测量和研究&#xff0c;我们可以更好地理解作物的生长状况&#xff0c;优化农业生产&#xff0c;提高作物产量和品质。但数籽粒数目是一个很繁琐和痛苦的过程&#xff0c;我们现在用一个简单的python程序来数水稻籽粒。代码的…

有限的边界-DDD领域

从广义上讲&#xff0c;领域&#xff08;Domain&#xff09;即是一个组织所做的事情以及其中所包含的一切。商业机构通常会确定一个市场&#xff0c;然后在这个市场中销售产品和服务。每个组织都有它自己的业务范围和做事方式。这个业务范围以及在其中所进行的活动便是领域。当…

Linux云计算之Linux基础3——Linux系统基础2

1、终端 终端(terminal)&#xff1a;人和系统交互的必要设备&#xff0c;人机交互最后一个界面&#xff08;包含独立的输入输出设备&#xff09; 物理终端(console)&#xff1a;直接接入本机器的键盘设备和显示器虚拟终端(tty)&#xff1a;通过软件方式虚拟实现的终端。它可以…

mysql的索引类型与数据存储

mysql索引与类型 什么是索引&#xff1f; 索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。我们可以简单理解为&#xff1a;快速查找排好序的一种数据结构。Mysql索引主要有两种结构&#xff1a;BTree索引和Hash索引。我们平常所说的索引&#xff0c;如…

web渗透-SSH私钥泄露

发现主机 netdiscover -r 192.168.164.0 扫描端口 看到开放80和31337端口都为http服务 浏览器访问测试 查看80端口和31337端口网页和源代码并无发现有用信息 目录扫描 扫描出80端口并无有用信息 扫描31337端口 发现敏感文件robots.txt和目录.ssh 访问敏感文件和目录 /.ss…

好物分享:FPGA实现SDI视频编解码的方案设计汇总

目录 1、前言2、专用芯片方案2.1、GS2971FPGA的图像采集 设计方案2.2、GS2971FPGA的图像采集图像缩放 设计方案2.3、GS2971FPGA的图像采集纯verilog图像缩放纯verilog视频拼接 设计方案2.4、GS2971FPGA的图像采集HLS图像缩放Video Mixer视频拼接 设计方案2.5、GS2971FPGA的图像…

Java单链表和LinkedList的实现

一、单链表的实现 无头单向非循环链表 定义异常用于判断所给位置是否合法 public class IndexNotLegal extends RuntimeException{public IndexNotLegal(){}public IndexNotLegal(String smg){super(smg);} } class ListNode中包含当前节点的值和下一个节点指向 实现链表的…

阿里云2024年优惠券领取及使用常见问题

阿里云是阿里巴巴旗下云计算品牌&#xff0c;服务涵盖云服务器、云数据库、云存储、域名注册等全方位云服务和各行业解决方案。为了吸引用户上云&#xff0c;阿里云经常推出各种优惠活动&#xff0c;其中就包括阿里云优惠券。本文将对阿里云优惠券领取及使用常见问题进行解答&a…

鸿蒙原生应用已超4000个!

鸿蒙原生应用已超4000个&#xff01; 来自 HarmonyOS 微博近期消息&#xff0c;#鸿蒙千帆起# 重大里程碑&#xff01;目前已有超4000个应用加入鸿蒙生态。从今年1月18日华为宣布首批200多家应用厂商正在加速开发鸿蒙原生应用&#xff0c;到3月底超4000个应用&#xff0c;短短…

DSOX3034T是德科技DSOX3034T示波器

181/2461/8938产品概述&#xff1a; 特点: 带宽:350 MHz频道:4存储深度:4 Mpts采样速率:5 GSa/s更新速率:每秒1000000个波形波形数学和FFT自动探测接口用于连接、存储设备和打印的USB主机和设备端口 触摸: 8.5英寸电容式触摸屏专为触摸界面设计 发现: 业界最快的无损波形更…

工业视觉检测

目录 我对工业视觉检测的了解 一、关键组成部分 二、应用场景 三、技术挑战 我对工业视觉检测的了解 工业视觉检测是利用机器视觉技术对产品质量进行自动化检查的过程&#xff0c;它在制造业中扮演着至关重要的角色&#xff0c;用于确保产品质量、提高生产效率、减少人工成…

小核引导RTOS---RISC-V C906

文章目录 参考日志编译框架目标fip 启动流程fip文件组成BL2程序 总结思考备注 参考 参考1. How does FSBL load the FreeRTOS on the small core and execute it?参考2. Duo now supports big and little cores?Come and play!Milk-V Duo, start&#xff01;参考3. 使用uboo…

ES学习笔记01

1.ES安装 下载地址&#xff1a; es官网下载 这里使用的是7.8.0的版本信息 下载完成后解压即可完成安装 2.启动运行 点击bin目录下的elasticsearch.bat文件即可启动 在浏览器中输入localhost:9200显示如下&#xff1a; 在路径中加入对应访问后缀即可访问对应信息 如&#…

【学习】移动端App性能测试流程有哪些

移动端App性能测试是保证App性能表现的重要环节之一。随着移动设备的普及和移动互联网的发展&#xff0c;移动端App的性能测试变得越来越重要&#xff0c;通过科学合理的性能测试可以发现并解决潜在的性能问题优化App运行效果提高用户体验。性能测试旨在评估App在各种场景下的性…

板材的加强筋优化-abaqus操作过程

前言 本示例详细讲解使用abaqus实现板材的加强筋优化的操作过程。 本页讨论 前言一、创建模型1.创建几何部件2.定义材料属性3.创建装配实体4.创建分析步5.创建边界条件及载荷6.划分网格7.创建分析作业并提交分析8.可视化后处理 二、设置优化1.创建优化任务2.创建设计响应3.创…

嵌入式软件工程师如何提高技术深度?

构建坚实且深厚的技术根基&#xff0c;其重要程度可谓举足轻重。唯有在对基础知识进行深入探究和理解的前提之下&#xff0c;方能够在理论的指引之下&#xff0c;持续地深入以及拓展技术领域。倘若缺乏稳固坚实的基础&#xff0c;那么深入开展研究便无从谈起。 在强调技术深度…

说说 HTTP1.0/1.1/2.0 的区别?

文章目录 一、HTTP1.0二、HTTP1.1三、HTTP2.0多路复用二进制分帧首部压缩 四、总结参考文献 一、HTTP1.0 HTTP协议的第二个版本&#xff0c;第一个在通讯中指定版本号的HTTP协议版本 HTTP 1.0 浏览器与服务器只保持短暂的连接&#xff0c;每次请求都需要与服务器建立一个TCP连…

bin、hex、exe、elf文件类型到底有何区别?如何解读hex文件和elf文件?...相关内容都在这里!

《嵌入式工程师自我修养/C语言》系列——bin、hex、exe、elf文件类型到底有何区别&#xff1f;readelf用法全面解读&#xff01; 一、常见文件类型之&#xff1a;bin、hex、elf、exe1.1 bin、hex、exe、elf文件类型到底有何区别&#xff1f;1.2 如何读懂一份hex文件&#xff1f…

数字人解决方案——Wav2lip本地部署

1、安装anaconda anaconda自行下载安装 2、下载wav2lip 在github中搜索wav2lip ​ git clone https://github.com/Rudrabha/Wav2Lip.git ​ 源码到本地 准备脸部检测预训练模型 下载地址&#xff1a;https://www.adrianbulat.com/downloads/python-fan/s3fd-619a316812…