Redis中线程IO模型是什么

这篇文章将为大家详细讲解有关Redis中线程IO模型是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

Redis是一个单线程的应用程序,NodeJs、Nginx都是单线程,它们都属于服务器高性能的典范。

Redis之所以是单线程还能这么快的原因:

其一是因为它所有的数据都在内存当中,所有的运算都是内存级别的运算,所以使用redis时,要注意时间复杂度为O(n)的指令,因为是单线程的,如果数据量太大,会让其他指令被阻塞等待;

其二是因为redis使用非阻塞IO与多路复用处理大量的客户端连接。

非阻塞IO

当我们使用套接字的读写方法时,默认是阻塞的,

即调用read方法传递一个参数n,表示最多读取n个字节后返回,如果一个字节都没有,线程就会在read方法这里持续等待,直到有数据过来或者连接被关闭,read方法此时返回,线程才能执行下面的逻辑,

write方法一般不会阻塞,除非内核为套接字分配的写缓冲区满了,write方法才会阻塞,一直到缓存区中有空间闲出来。

下图是套接字读写的细节流程。

Redis中线程IO模型是什么  redis 第1张

非阻塞IO在使用套接字时提供了一个选项Non_Blocking,当这个选项打开时,读写方法不会阻塞,而是能读多少读多少,能写多少写多少,

能读多少取决与内核为套接字分配的读缓冲区的数据字节数,能写多少取决于内核为套接字写缓冲区分配的数据字节数,

读写方法都会通过返回值告诉程序读写了多少字节数。

非阻塞IO意味着读写时,线程不必再被阻塞着,读写可以瞬间完成,线程可以继续往下做别的事情。

多路复用(事件轮询)

非阻塞IO虽然很快,但是也带来一个问题,线程读数据,读了一部分就返回了,没有读完,剩下的数据何时继续读?,写数据,缓冲区满了,没有写完,剩下的数据何时继续写?

当可以继续读或者可以继续写时,应该给应用程序一个通知,告诉应用程序可以继续读或者继续写,事件轮询API就是用来处理这个问题的。

select

操作系统提供了一个select函数给用户程序,输入是读写描述符列表 read_fds & write_fds,输出是与之对应的可读可写事件,

同时还提供了timeout参数,线程最多等待timeout的时间,在这期间有事件过来,方法立刻返回,线程往下处理,如果超过timeout时间,方法也会返回,

如果拿到事件了,线程即可挨个处理相应的事件,处理完了以后继续调用 select api 轮询,所以该线程其实是一个死循环,不停的 select,不停的处理,来回这样,这个死循环被称之为事件循环,一个循环即一个周期。

Redis中线程IO模型是什么  redis 第2张

事件循环伪代码:

while True
    read_events, write_events = select(read_fds, write_fds, timeout)
    for event in read_events:
        handle_read(event.fd)
    for event in write_events:
        handle_write(event.fd)
    handle_others() # 做其他的逻辑处理,处理定时任务等等

通过select函数我们可以处理多个通道描述符的读写事件,所以将select这类的系统函数调用称之为多路复用API,

现代操作系统的多路复用API已经不使用select系统调用,改用epoll(linux)和kqueue(FreeBSD、macosx),

select的性能在描述符变多时会变得很差,epoll与select使用起来略有差异,不过都可以用上面的伪代码理解,都是当描述符发生事件时,循环对描述符的事件做出处理,

serversocket对象的读操作是指调用accept接受客户端新连接,何时有连接来临,也是通过select调用的读事件通知的。

Java中的NIO技术就是事件轮询,其他语言也有这个技术。

指令队列

Redis为每一个客户端套接字关联一个指令队列,客户端发来的指令通过队列进行先进先出的顺序处理。

响应队列

同样Redis返回的结果也通过为每个客户端关联的一个队列返回,如果队列为空,则暂时不需要去获取写事件,

此时会将该客户端描述符从write_fds里移除,等队列有数据的时候,再将描述符放进去,这样可以避免select系统调用返回写事件时,发现没数据可写,造成空轮询、无用轮询,对机器CPU的消耗。

定时任务

服务器不单要响应IO事件,有些其他的事情也需要处理,例如应用程序自身的定时任务,如果线程阻塞在select调用上,等待select的返回,这会造成有些定时任务到期了,却没有执行,

Redis的定时任务记录在一个称为 最小堆 的数据结构中,这个堆中,最快要执行的任务排在最上方,每个循环周期里,redis会对堆中已经到时间点的任务进行处理,

处理完毕后,将堆中即将要执行的任务还需要的时间记录下来,再次调用select时,这个时间就是timeout的值,在这期间内不会有其他任务需要执行了,redis可以放心的最多阻塞这么久,然后到时间后进行相应的处理。

NodeJs和Nginx的事件处理原理和Redis也是类似的形式。

关于“Redis中线程IO模型是什么”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

评论

有免费节点资源,我们会通知你!加入纸飞机订阅群

×
天气预报查看日历分享网页手机扫码留言评论电报频道链接