【redis学习】Redis-IO多路复用
为什么要有IO多路复用大家印象中的redis都是单线程的,没有加锁的操作,因此才会是redis这么快的原因其中之一。先暂且不说redis究竟是不是单线程,即便是单线程的,作为服务提供方,面对成百上千的客户端毗连哀求,读写操作,单线程是怎么做到高效的处理惩罚这些哀求?单线程处理惩罚socket毗连,面对客户端发送的指令怎样处理惩罚?一个个轮询吗?明显是比较低效的操作,作为高效著称的redis肯定是不会用这么简单粗暴的方式行止理的。这里就引出一个办理方式IO多路复用。
在redis6/7中,非常受关注的第一个新特性就是多线程。
redis一直被大家熟知的就是它的单线程架构,虽然有的命令操作可以用后台线程或者子进程实行(好比数据删除,快照生成,AOF重写)。但是,从网络IO处理惩罚到现实的读写命令处理惩罚,都是由单个线程完成的。
为了应对这个题目,采用多个IO线程来处理惩罚网络哀求,提高网络哀求处理惩罚的并行度,Redis6/7就是采用的这种方法。
但是redis的多IO线程只是用来处理惩罚网络哀求的,对于读写操作命令Redis仍旧使用单线程来处理惩罚。这是因为redis处理惩罚哀求时,网络处理惩罚常常是瓶颈,通过多个IO线程并行处理惩罚网络操作,可以提拔实例的整体处理惩罚性能。而继续使用单线程实行命令操作,就不用为了保证Lua脚本,事务的原子性,额外开辟多线程互斥加锁机制了,如许一来redis线程模型实现就简单了。
什么是IO多路复用
网络IO在体系层面上指的是数据从用户态到内核态的读写操作,多路是指多个socket毗连。在UNIX网络编程中写道为了实行网络IO,一个进程必须要做的第一件事就是调用socket函数。复用是指一个或多个毗连处理惩罚。
一个服务端进程可以同时处理惩罚多个套接字形貌符。
redis使用IO多路复用简单来说就是,单线程处理惩罚多个客户端毗连的网络读写哀求,并且能够保证不会阻塞主流程的一种机制。
实现IO多路复用的模型有3种:可以分select->poll->epoll三个阶段来形貌。
根本IO模型与阻塞点
以Get哀求为例,服务端为了处理惩罚一个Get哀求,需要监听客户端哀求(bind/listen),和客户端创建毗连(accept),从scoket中读取哀求(recv),剖析客户端发送哀求(parse),根据哀求类型读取键值数据(get),最后客户端返回结果,即向socket中写回数据(send)。
下图表现了这一过程,其中,bind/listen、accept、recv、parse和send属于网络IO处理惩罚,而get属于键值数据操作。既然Redis是单线程,那么,最根本的一种实现是在一个线程中依次实行上面说的这些操作。
https://i-blog.csdnimg.cn/blog_migrate/583bd7a5a23c6c5c159c9208993b31f6.png
但是,在这里的网络IO操作中,有潜伏的阻塞点,分别是accept()和recv()。当Redis监听到一个客户端有毗连哀求,但一直未能成功创建起毗连时,会阻塞在accept()函数这里,导致其他客户端无法和Redis创建毗连。类似的,当Redis通过recv()从一个客户端读取数据时,如果数据一直没有到达,Redis也会一直阻塞在recv()。这就导致Redis整个线程阻塞,无法处理惩罚其他客户端哀求,效率很低。
以上形貌的就是在阻塞式socket大概会出现的阻塞点。假设一个socket被阻塞在其中某一个步调,那么其他的socket也将会被阻塞住。这种情况肯定是不能容忍的。荣幸的是socket网络模型本身支持非阻塞式。
非阻塞模式
Socket网络型的非阻塞式模式设置,告急表现在三个关键的函数调用上,如果想使用socket非阻塞模式,就必须要了解这三个函数的调用返回类型和设置模式。
在socket模型中,差别操作调用后返回差别的套接字类型。socket()方法会返回自动套接字,然后调用listen()方法,将自动套接字转换为监听套接字,此时,可以监听来自客户端的哀求毗连。最后调用accpet()方法接受到的客户端毗连,并返回已毗连套接字。
https://i-blog.csdnimg.cn/blog_migrate/cce62727b2dd60f0d682b1eb78c9054d.png
针对监听套接字,可以设置非阻塞模式:当redis调用accpet()单一直未有毗连哀求到达时,redis线程可以返回处理惩罚其他操作,而不用一直等待。
虽然redis线程可以不用继续等待,但是总得有机制继续在监听套接字上等待后续毗连哀求并且在有哀求时通知redis。
同样也可以针对已毗连套接字设置非阻塞模式:在redis调用recv()后,如果已毗连套接字上一直没有数据到达,redis线程同样可以返回处理惩罚其他操作。也需要有机制继续监听已毗连套接字,并在有数据到达时通知redis。
如许才气保证redis线程,既不会像根本IO模型中一直在阻塞点等待,也不会导致redis无法处理惩罚现实到达的毗连哀求或数据。
那么这个机制究竟是什么来实现的?
简述多路复用模型
将用户socket对应的文件形貌符注册进epoll,然后epoll监听哪些scoket上有消息到达,如许就避免了大量的无用操作。设置sokcet模型为非阻塞模式,如许整个过程只在调用epoll这些的时候才会阻塞。收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是变乱驱动,所谓的reactor响应模式。至此我们明确了用于监听变乱拉起通知的机制是通过epoll这些来实现管理的。
Linux中的IO多路复用机制是指一个线程处理惩罚多个IO流,就是我们常常听到的select/epoll机制。简单来说在redis只运行单线程的情况下,该机制允许内核中同事存在多个监听套接字和已毗连套接字。内核会一直监听这些套接字上的毗连哀求或数据哀求。一旦有哀求到达,就会交给redis线程处理惩罚,这就是实现了一个redis线程处理惩罚多个IO流的效果。
下图就是基于多路复用的redis IO模型。图中的多个FD就是刚才所说的多个套接字。Redis网络框架调用epoll机制,让内核监听这些套接字。此时Redis线程不会阻塞在某一个特定的监听或者已毗连套接字上,也就是说,不会阻塞在某一个特定的客户端哀求处理惩罚上。正因为此,redis可以同时和多个客户端毗连并处理惩罚哀求,从而提拔并发性。
https://i-blog.csdnimg.cn/blog_migrate/89652021fd22f34b99329bf985e66111.png
为了在哀求到达时能够通知到redis线程,select/epoll提供了基于变乱的回调机制,即针对差别变乱的发生,调用相应的处理惩罚函数。
那么,回调机制是怎么工作的?实在select/epoll一旦监听到FD上有哀求到达时,就会触发相应的变乱。
这些变乱会被放进一个变乱队列,redis单线程对该变乱队列不断进行处理惩罚。如许一来,redis无需一直轮询是否有哀求现实发生,这就可以避免造成CPU资源浪费。同时redis在对变乱队列中的变乱进行处理惩罚时,会调用相应处理惩罚函数。这就实现了基于变乱的回调。因为redis一直在对时间队列进行处理惩罚,以是能够及时响应客户端哀求,提拔redis的响应性能。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]