首页 > 数据库 >Redis网络模型,IO多路复用

Redis网络模型,IO多路复用

时间:2023-02-10 00:00:11浏览次数:34  
标签:多路复用 Redis 阻塞 FD 内核 IO 就绪 监听

IO多路复用

无论是阻塞l0还是非阻塞lO,用户应用在一阶段都需要调用recvfrom来获取数据,差别在于无数据时的处理方案:

*如果调用recvfrom时,恰好没有数据,阻塞IO会使进程阻塞,非阻塞IlO使CPU空转,都不能充分发挥CPU的作用。

*如果调用recvfrom时,恰好有数据,则用户进程可以直接进入第二阶段,读取并处理数据


比如服务端处理客户端Socket请求时,在单线程情况下,只能依次处理每一个socket,如果正在处理的socket恰好未就绪(数据不可读或不可写),线程就会被阻塞,所有其它客户端socket都必须等待,性能自然会很差。
这就像服务员给顾客点餐,分两步:
1,顾客思考要吃什么(等待数据就绪)
2,顾客想好了,开始点餐(读取数据)

要提高效率有几种办法?

方法一:增加服务员(多线程),缺点:切换上下文开销也很大

方法二:不排队,谁想好吃什么了(数据就绪了),服务员就给谁点餐(用户应用就去读取数据)

那么问题来了,用户进程如何知道谁就绪了呢?

文件描述符(File Descriptor):简称FD,是一个从零开始递增的无符号整数,用来关联linux中的一个文件。在Linux中一切皆文件,例如常规文件,视频,硬件设备等,当然也包括网络套接字(socket)。

IO多路复用就是:利用单个线程来监听多个FD,并在某个FD可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。

与BIO(阻塞IO)和NIO(非阻塞IO)不同的是,BIO和NIO在调用内核态时,都是直接调用recvfrom方法,但是在调用时,用户空间是不知道内核空间的数据是否就绪的,如果数据没有就绪就会造成阻塞。

所以,多路IO会先调用select方法同时监听多个sockets,并阻塞等待数据(如果数据都没就绪的话),一旦内核空间有数据就绪了,内核空间会通知用户空间有数据就绪了,再去调用recvfrom方法。

不过监听FD的方式、通知的方式又有多种实现,常见的有,select,poll,epoll。

select和poll只会通知有FD就绪,但不确定具体是哪个FD,需要用户进程逐个遍历FD来确认。

epoll则会在通知用户进程FD就绪的同时,把已经就绪的FD写入用户空间。

IO多路复用-Epoll

FD是以红黑树形式存储在内核空间的,就绪的FD会以链表形式存储。

将一个FD添加到红黑树中时,会设置一个回调函数,ep_poll_callback监听FD,callback触发时,就把对应的FD加入到rdlist这个就绪列表中。

 

 

Select,Poll,Epoll的总结:

Select模式的三大问题:

能监听的FD最大不超过1024

每次select都要把所有要监听的FD都拷贝到内核空间

每次都要遍历所有的FD来判断就绪状态

Poll模式的问题:

poll利用了链表来解决select中监听上限的问题,但依然要遍历所有的FD,如果监听太多,性能会下降,理论上来讲是无限的,但是实际使用中不允许很多的FD。

Epoll模式是如何解决上述问题的?

基于epoll实例中的红黑树保存要监听的FD,理论上无上限,而且增删改查效率都非常高,性能不会随监听的FD数量多而变差。

每个FD只需要执行一个epoll_ctl添加到红黑树,以后每次epol_wait无需传递任何参数,无需重复拷贝FD到内核空间。

内核会将就绪的FD直接拷贝到用户空间的指定位置,用户进程无需遍历所有FD就能知道就绪的FD是谁。

 

标签:多路复用,Redis,阻塞,FD,内核,IO,就绪,监听
From: https://www.cnblogs.com/tyleaf/p/17107483.html

相关文章