专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

Redis属于单线程还是多线程?不同版本之间有什么区别?

  Redis是单线程还是多线程
  Redis应该是使用频率最高的组件之一了,不仅在工作中会大量使用,面试的时候也经常会作为考点出现,下面就来深入地了解一下Redis。
  先来探讨一个问题,Redis使用的到底是多线程还是单线程?
  不同版本的Redis是不同的,在4。0之前Redis是单线程运行的,但是单线程并不代表效率低。像Nginx、Nodejs也是单线程程序,但它们的效率并不低,因为底层采用了基于epoll的IO多路复用(后面说)。
  此外Redis是基于内存操作的,它的瓶颈在于机器的内存、网络带宽,而不是CPU,因为在你CPU还没达到瓶颈时你的内存可能就先满了、或者带宽达到瓶颈了。因此CPU不是主要原因,那么自然就采用单线程了。更何况使用多线程还会面临一些额外的问题,比如共享资源的保护等等,对于一个CPU不是主要瓶颈的键值对数据库而言,采用单线程是非常合适的。
  简单来说,Redis在4。0之前使用单线程的模式是因为以下三个原因:使用单线程模式的Redis,其开发和维护会更简单,因为单线程模型方便开发和调试;即使使用单线程模型也能够并发地处理多客户端请求,因为Redis内部使用了基于epoll的多路复用;对于Redis而言,主要的性能瓶颈是内存或者网络带宽,而并非CPU;
  但Redis在4。0以及之后的版本中引入了惰性删除(也叫异步删除),这是由额外的线程执行的。意思就是我们可以使用异步的方式对Redis中的数据执行删除操作了,例如:unlinkkey,flushdbasync,flushallasync,举个例子:127。0。0。1:6379setnamesatoriOK127。0。0。1:6379getnamesatori这里是异步删除一个key同步的话则是delname127。0。0。1:6379unlinkname(integer)1127。0。0。1:6379flushdbasyncOK127。0。0。1:6379flushallasyncOK
  这样处理的好处就是不会使Redis的主线程卡顿,会把这些删除操作交给后台线程来执行。
  通常情况下使用del指令可以很快地删除数据,但是当被删除的key是一个非常大的对象时,例如:删除的是包含了成千上万个元素的hash集合,那么del指令就会造成Redis主线程卡顿。而使用惰性删除,可以有效地避免Redis卡顿的问题。
  除了惰性删除,像持久化、集群数据同步等等,都是由额外的子线程执行的,而Redis主线程则专注于网络IO和键值对读写。单线程的Redis为什么这么快
  正如上面所说,Redis4。0之前是单线程的,那既然是单线程为什么速度还能那么快?吞吐量还能那么高?
  原因有以下几点:
  1)基于内存操作:Redis的所有数据都在内存中,因此所有的运算都是内存级别的,所以它的性能比较高;
  2)数据结构简单:Redis的数据结构是为自身专门量身打造的,而操作这些数据结构的时间复杂度是O(1);
  3)多路复用和非阻塞IO:Redis使用IO多路复用功能来监听多个socket连接客户端,这样就可以使用一个线程来处理多个连接,从而减少线程切换带来的开销,同时也避免了IO阻塞操作,从而大大地提高了Redis的性能;
  4)避免上下文切换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的开销,而且单线程不会导致死锁的问题发生;非阻塞IO和IO多路复用是什么
  首先我们可以使用get命令,获取一个key对应的value,比如:127。0。0。1:6379getnamesatori
  那么问题来了,以上对于Redis服务端而言,都发生了哪些事情呢?
  服务端必须要先监听客户端连接(bindlisten),然后当客户端到来时与其建立连接(accept),从socket中读取客户端的请求(recv),对请求进行解析(parse)。这里解析出的请求类型是get、key是name,再根据key获取对应value,最后返回给客户端,也就是向socket写入数据(send)。
  以上所有操作都是由Redis主线程依次执行的,但里面会有潜在的阻塞点,分别是accept和recv。
  当Redis监听到一个客户端有连接请求、但却一直未能成功建立连接,那么主线程会一直阻塞在accept函数这里,导致其它客户端无法和Redis建立连接。
  类似的,当Redis通过recv从客户端读取数据时,如果数据一直没有到达,那么Redis主线程也会一直阻塞在recv这一步,因此这就导致了Redis的效率会变得低下。
  非阻塞IO
  但很明显,Redis不会允许这种情况发生,因为以上都是阻塞IO会面临的情况,而Redis采用的是非阻塞IO,也就是将socket设置成了非阻塞模式。
  首先在socket模型中,调用socket()方法会返回主动套接字,调用bind()方法绑定IP和端口,再调用listen()方法将主动套接字转化为监听套接字,最后监听套接字调用accept()方法等待客户端连接的到来,当和客户端建立连接时再返回已连接套接字,而后续就通过已连接套接字来和客户端进行数据的接收与发送。
  但是注意:我们说在listen()这一步,会将主动套接字转化为监听套接字,而此时的监听套接字的类型是阻塞的,阻塞类型的监听套接字在调用accept()方法时,如果没有客户端来连接的话,就会一直处于阻塞状态,那么此时主线程就没法干其它事情了。
  所以在listen()的时候可以将其设置为非阻塞,而非阻塞的监听套接字在调用accept()时,如果没有客户端连接到达时,那么主线程就不会傻傻地等待了,而是会直接返回,然后去做其它的事情。
  类似的,我们在创建已连接套接字的时候也可以将其类型设置为非阻塞,因为阻塞类型的已连接套接字在调用send()recv()的时候也会处于阻塞状态。比如当客户端一直不发数据的时候,已连接套接字就会一直阻塞在recv()这一步。如果是非阻塞类型的已连接套接字,那么当调用recv()但却收不到数据时,也不用处于阻塞状态,同样可以直接返回去做其它事情。
  但是有两点需要注意:
  1)虽然accept()不阻塞了,在没有客户端连接时Redis主线程可以去做其它事情,但如果后续有客户端连接,Redis要如何得知呢?因此必须要有一种机制,能够继续在监听套接字上等待后续连接请求,并在请求到来时通知Redis。
  2)send()recv()不阻塞了,相当于IO读写流程不再是阻塞的,读写方法都会瞬间完成并返回,也就是说它会采用能读多少就读多少、能写多少就写多少的策略来执行IO操作,这显然更符合我们对性能的追求。
  但这样会面临一个问题,那就是当我们执行读取操作时,有可能只读取了一部分数据,剩余的数据客户端还没发过来,那么这些数据何时可读呢?同理写数据也是这种情况,当缓冲区满了,而我们的数据还没有写完,那么剩下的数据又何时可写呢?因此同样要有一种机制,能够在Redis主线程做别的事情的时候继续监听已连接套接字,并且在有数据可读写的时候通知Redis。
  这样才能保证Redis线程既不会像基本IO模型一样,一直在阻塞点等待,也不会无法处理实际到达的客户端连接请求和可读写的数据,而上面所提到的机制便是IO多路复用。
  IO多路复用
  IO多路复用机制是指一个线程处理多个IO流,也就是我们经常听到的selectpollepoll,而Linux默认采用的是epoll。
  简单来说,在Redis只运行单线程的情况下,该机制允许内核中同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求,一旦有请求到达就会交给Redis线程处理,这样就实现了一个Redis线程处理多个IO流的效果。
  上图就是基于多路复用的RedisIO模型,图中的FD就是套接字,可以是监听套接字、也可以是已连接套接字,Redis会通过epoll机制来让内核帮忙监听这些套接字。而此时Redis线程或者说主线程,不会阻塞在某一个特定的套接字上,也就是说不会阻塞在某一个特定的客户端请求处理上。因此Redis可以同时和多个客户端连接并处理请求,从而提升并发性。
  但为了在请求到达时能够通知Redis线程,epoll提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。
  那么回调机制是怎么工作的呢?以上图为例,首先epoll一旦监测到FD上有请求到达,就会触发相应的事件。这些事件会被放进一个队列中,Redis主线程会对该事件队列不断进行处理,这样一来Redis就无需一直轮询是否有请求发生,从而避免资源的浪费。
  同时,Redis在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为Redis一直在对事件队列进行处理,所以能及时响应客户端请求,提升Redis的响应性能。
  比如连接请求和数据读取请求分别对应Accept事件和Read事件,Redis分别对这两个事件注册accept和get回调函数。当Linux内核监听到有连接请求或数据读取请求时,就会触发Accept事件或Read事件,然后内核就会回调Redis注册的accept函数或get函数。
  就像病人去医院看病,在医生实际诊断之前每个病人(类似于请求)都需要先分诊、测体温、登记等等。如果这些工作都由医生完成,那么医生的工作效率就会很低。所以医院设置了分诊台,分诊台会一直处理这些诊断前的工作(类似于Linux内核监听请求),然后再转交给医生做实际诊断,这样即使一个医生(相当于Redis的主线程)也能有很高的效率。
  需要注意的是,不同的操作系统有着不同的多路复用实现,除了Linux的epoll,还有FreeBSD的kqueue、以及Solaris的evport。相关视频推荐
  源码调试:redisio多线程
  redis为什么是单线程?这里单线程指什么?redis单线程为什么这么快?
  需要CCLinux服务器架构师学习资料加qun812855908获取(资料包括CC,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCPIP,协程,DPDK,ffmpeg等),免费分享
  嗦一下Redis6。0的多线程
  Redis6。0引入了一些新特性,其中非常受关注的一个特性就是多线程。在4。0之前Redis是单线程的,因为单线程的优点很明显,不但降低了Redis内部实现的复杂性,也让所有操作都可以在无锁的情况下进行,并且不存在死锁和线程切换带来的性能以及时间上的消耗。
  但是其缺点也很明显,单线程机制导致Redis的QPS(QueryPerSecond,每秒查询数)很难得到有效的提高(虽然已经够快了,但人毕竟还是要有更高的追求的)。
  然后Redis在4。0版本引入了多线程,但是此版本的多线程主要用于大数据量的异步删除,对于非删除操作的意义并不是很大。
  而Redis6。0中的多线程则是真正为了提高IO的读写性能而引入的,它的主要实现思路是将主线程的IO读写任务拆分给一组独立的子线程去执行。也就是说,从socket读数据和写数据不再由主线程负责,而是交给了多个子线程,这样就可以使多个socket的读写并行化了。这么做的原因就在于,虽然在Redis中使用了IO多路复用和非阻塞IO,但数据在内核态空间和用户态空间之间的拷贝是无法避免的,而数据的拷贝这一步是阻塞的,并且当数据量越大时拷贝所需要的时间就越多。
  所以Redis在6。0引入了多线程,用于分摊同步读写IO压力,从而提升Redis的QPS。
  但是注意:Redis的命令本身依旧是由Redis主线程串行执行的,只不过具体的读写操作交给独立的子线程去执行了(一会儿详细说明Redis的主线程和子线程之间是如何协同的)。而这么做的好处就是不需要为Lua脚本、事务的原子性而额外开发多线程互斥机制,这样一来Redis的线程模型实现起来就简单多了。因为和之前一样,所有的命令依旧是由主线程串行执行,只不过具体的读写任务交给了子线程。
  除了引入多线程,还可以将内核网络协议栈换成用户态网络协议栈(DPDK),让网络请求不在内核里进行,直接在用户态完成。但Redis并没有采用这种做法,虽然替换协议栈可以避免频繁地让内核参与网络请求处理,提升请求处理效率。原因是该做法要求Redis添加对用户态网络协议栈的支持,需要修改Redis源码中和网络相关的部分,这会带来很多额外的开发工作量;而且新增代码还可能引入bug,导致Redis程序不稳定,因此Redis6。0没有采用这种做法。请再具体嗦一下Redis6。0的主线程和子线程之间是如何协同的?
  整体可以分为四个阶段。
  阶段一:服务端和客户端建立socket连接,并分配子线程(处理线程)
  首先,主线程负责建立连接请求,当有客户端请求到达时,主线程会创建和客户端的scoket连接,该socket连接就是用来和客户端进行数据传输的。只不过这一步不由主线程来做,主线程要做的事情是将该socket放入到全局等待队列中,然后通过轮询的方式选择子线程,并将队列中的socket连接分配给它。
  所以无论是从客户端读数据还是向客户端写数据,都由子线程来做。因为我们说Redis6。0引入的多线程就是为了缓解主线程的IO读写压力,而IO读写这一步是阻塞的,所以应该交给子线程并行操作。
  阶段二:子线程读取并解析请求
  主线程一旦把socket连接分配给子线程,那么会进入阻塞状态,等待子线程完成客户端请求的读取和解析,得到具体的命令操作。由于可以有多个子线程,所以这个操作很快就能完成。
  阶段三:主线程执行命令操作
  等到子线程读取到客户端请求并解析完毕之后,再由主线程以单线程的方式执行命令操作,所以IO读写虽然交给了子线程,但命令本身还是由Redis主线程执行的。
  阶段四:子线程回写socket、主线程清空全局队列
  当主线程执行完命令操作时,还需要将结果写入缓冲区,而这一步显然要由子线程来做,因为是IO读写。此时主线程会再次陷入阻塞,直到子线程将这些结果写回socket并返回给客户端。
  和读取一样,子线程将数据写回socket时,也是多个线程在并行执行,所以写回socket的速度也很快。之后主线程会清空全局队列,等待客户端的后续请求。
  在Redis6。0中如何开启多线程?
  在了解了Redis6。0的多线程机制之后,我们要如何开启多线程呢?在Redis6。0中,多线程机制默认是关闭的,如果想启动的话,需要修改redis。conf里的两个配置。设置iothreaddoreads配置项为yes表示启用多线程iothreaddoreadsyes通过iothreads设置子线程的数量iothreads3
  上述配置表示开启3个子线程,需要注意的是,线程数并不是越大越好,应该小于机器的CPU核数。关于线程数的设置,官方的建议是:如果4核的CPU,那么设置子线程数为2或3;如果8核的CPU,那么设置子线程数为6。
  如果你在实际应用中,发现Redis实例的CPU开销不大,吞吐量却没有提升。那么可以考虑使用Redis6。0的多线程机制,加速IO读写处理,进而提升实例的吞吐量。
  最后关于Redis的性能,Redis的作者在2019的RedisConf大会上提到,Redis6。0引入的多线程IO特性对性能的提升至少是一倍以上。国内也有人在阿里云使用4个线程的Redis版本和单线程的Redis版本进行比较测试,发现测试的结果和Redis作者说的一致,性能基本可以提高一倍。小结
  以上我们就介绍了Redis在4。0之前明明采用单线程但却依然快的原因:基于内存操作、量身打造的数据结构、IO多路复用和非阻塞IO、避免了不必要的线程上下文切换。
  并且在Redis4。0开始支持多线程,主要体现在大数据的异步删除上面,例如:unlinkkey、flushdbasync、flushallasync等。
  而Redis6。0的多线程则增加了对IO读写的并发能力,因为数据在用户态和内核态之间穿梭是需要进行拷贝的,而这一步会阻塞,所以通过多个线程并行操作能更好地提升Redis的性能。

CBA3消息周鹏担任男篮队长,杜锋考察陈国豪,四川签约克劳福德中国男篮即将迎战哈萨克斯坦队,据记者宋翔透露,周鹏将担任新一届男篮队长一职,在上一个窗口期,周鹏重返国家队,在对阵伊朗队巴林队的两场比赛中,展现出了不俗的竞技状态,连续两场命中关键沃恩谈小库里现在他是丁威迪的替补,他能控球也能打无球篮网主帅雅克沃恩表示他会暂时把塞思库里视为一名替补控卫。沃恩说我们在上一场比赛中把他作为替补。他顶替丁威迪上场,他能控球也能打无球。所以我们会尽量利用这一点。我们已经见过他面对不同莫兰特乔丹那么厉害,为何月周最佳不到詹姆斯一半,别活在过去莫兰特现在也可以说经过几个赛季的打磨,渐渐的也显现出有一线球星的潜力,目前场均24也能排在联盟得分前10,所以莫兰特说的一些话还是比较有争议的,主持人问莫兰特,你认为乔丹厉害还是老三笔签约正式达成!勇士报价唐斯,灰熊报价戴维斯北京时间2月23日,NBA全明星周末刚刚结束,虽然各支球队还没有开始正式的比赛,但是自由球员市场上依然热闹非凡,就在刚刚结束的一上午,联盟就有三笔签约正式完成,并且有三笔交易正在商为什么西方不敢招惹我国?只是因为这三个盟友我国才屹立不倒普京曾经说过,现在没一个国家敢侮辱我国。老美网民批评,为什么没一个国家敢在这三个主要盟友的保护之下轻易侮辱我国。老美网友的这些问题,可说是问到了西方军事专家的心。便是因为我国有了这我国首颗超百Gbps容量高通量卫星成功发射2月23日19时49分,我国在西昌卫星发射中心使用长征三号乙运载火箭,将中星26号卫星发射升空。卫星顺利进入预定轨道,发射任务获得圆满成功。新华社发史悦摄我国首颗超百Gbps容量高元宇宙虚拟空间Web3全球49位专家对2023最火爆科技的预测编者按2022年对科技行业来说是非常热闹的一年。我们关注着埃隆马斯克(ElonMusk)的大戏,惊叹于生成式人工智能的创造,目睹了加密市场暴跌和FTX崩溃,深深凝视着元宇宙2023东三省行游影记(110)长春护国般若寺8月4日,早晨630起床,收拾完在房间吃自制早餐,煮蛋,杠头,辣白菜,还有昨晚在永辉超市买的君乐宝酸奶,一顿丰盛的早餐在房中解决了。早餐后开始今天的行游,今天的计划是游览人民大街,影记天津意式风情区原创影记津门游记06天津意式风情区天津意式风情区,简称意风区,坐落于海河之滨,地处天津市河北区,是由五经路博爱道胜利路建国道合围而成的四方形地区。这里原来曾是意大利租界,是意大利在地球名地览3尼罗河头条创作挑战赛尼罗河是世界第一长河,全长6740千米,流域面积280万平方千来,是非洲大陆面积的110,大部分在埃及和丹境内。它发源于赤道以南非洲东部高原,由南向北纵贯及全境沿途经今春南海子公园迎来首批天鹅歇脚北京日报客户端记者刘平2月22日傍晚,伴随着夕阳西下,太阳在南海子公园水面洒下金色余晖,刚刚飞抵南海子的首批天鹅在金色水面上不时游动着,近30只天鹅成为搅动金色水面的精灵,呈现为一
杨虎城遇害57年后,孙子杨瀚找到真凶,笑着说祝您活到110岁1949年,军统特务按照蒋介石的旨意,对杨虎城将军下了毒手。杨虎城的嫡孙杨瀚,出生在爷爷被害之后,虽然他没有见过爷爷,但是从家人口中了解到了爷爷的一些事情,随着年龄的慢慢增长,杨瀚历史上有三大姓氏,从未衰败,已兴盛了3000年,是你的姓氏吗?中国历史悠长,衍生出了许多璀璨的文化。其中,姓氏作为伴随我们每个人一生的符号,具有十分深远的意义。据中国姓氏纪编的统计,中国共有5730个姓氏,其中一部分的姓氏,已经被历史的洪流所发言权和行动权中国网三农3月9日载,由于局势动荡不安,连大学者鲁迅的日子也不好过,再加上时任厦大校长林文庆非常吝啬,欲将办学经费减少一半,受到该校教授学者们的强烈反对,情急之下该校长竟然指着桌子拿破仑的一点事拿破仑的经历拿破仑波拿巴(NapoleonBonaparte)是18世纪末19世纪初欧洲历史上最著名的人物之一。他于1769年8月15日出生在科西嘉岛(Corsica)的阿雅克肖(蔚来,退车!扬子晚报网3月14日讯(记者万凌云)蔚来辅助驾驶中包含自动刹车功能吗?ES8顶配蔚来高速上追尾4人受伤,2月21日22日,扬子晚报紫牛新闻相继独家报道了镇江市民蒋先生和朋友高速上驾21私募投融资周报(3。63。12)视微影像完成国寿股权与前海方舟领投超3亿元C轮融资,小菜园获加华资本数千万美元投资新的一周开始,简单回顾上周披露的投资融资交易。消费服务领域新披露融资中,相对活跃的投资机构包括山海资本加华资本等,豆校长荣获A轮融资5000万,山海资本参投大众餐饮连锁企业小菜园获冉莹颖近照曝光,穿着太过清凉!拳王妻子总是不够朴素在最近的一档家庭综艺节目中,世界拳王邹市明和妻子冉莹颖被推荐为邀约嘉宾,理由是这对夫妻既开朗豪爽又风趣好玩,他们俩上节目肯定很刺激。随后,有网友将冉莹颖带着孩子出席活动的照片发了出价值3万元的快递被烧毁,快递公司被起诉现代快报讯(通讯员石玉孟良燕记者严君臣)王某寄了一箱价值3万元的衣物,没想到运输车辆着火,快递货物灭失。王某要求快递公司全额赔偿损失,但快递公司以王某未保价为由,只同意按运费的7倍价值3万元的快递被烧毁,快递公司只肯赔7倍运费现代快报讯(通讯员石玉孟良燕记者严君臣)王某寄了一箱价值3万元的衣物,没想到运输车辆着火,快递货物灭失。王某要求快递公司全额赔偿损失,但快递公司以王某未保价为由,只同意按运费的7倍超震撼!荆门将迎花海旅游季巨型稻草人王国,3月25日起迎客!领票啦春雾绕荆门,花香随风至当数万株虞美人即将花开成海当万千郁金香正含苞待放之时一场震撼的春游之旅将拉开帷幕3月25日起荆门花海季巨型稻草人王国迎客来自全国各地数十位大地艺术家相约荆门圣大鹏,好彩!大鹏四季歌早春时节,气温回升,各种花卉如约赶赴春天的盛宴,山海大鹏花繁景明。谢雨婷摄谢雨婷摄禾塘山水公园里,宫粉紫荆持风落笔描绘粉色浪漫排牙山下,油菜花盛开装扮靓丽大鹏碧道边,满眼青翠大鹏中
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网