Nginx异步非阻塞

2020-03-27  本文已影响0人  全栈小运维

在使用socket编程中,经常会看到阻塞、非阻塞、同步、异步,那么它们之间到底有什么关系跟区别呢?
本次将那Nginx的异步非阻塞的事件驱动模型来解释一下它们之间的关系。

阻塞IO

在linux中,默认所有socket都是阻塞的。

这意味着使用该socket调用诸如recv的函数时,在没有数据到达之前,该函数将不会返回,导致线程被阻塞,直到数据到达。

非阻塞IO

我们可以使用fcntl把socket设置为非阻塞的。

这意味着使用该socket调用诸如recv的函数时,该函数将立刻返回,可以根据返回值来确定是否有数据到达。

相信阻塞/非阻塞IO的大家都非常的清楚,本次主要说的是同步IO跟异步IO之间的区别。

首先要说的是,同步/异步只是跟具体实现有关,就是说非阻塞的必定是异步的的说法是错误的,它们之间并没有确定的关系。

同步IO

一般来说,我们调用的函数都是同步的。

何为同步呢?就是说我们调用了一个函数,在该函数返回之后就说明该函数要做的东西已经完成了。

这是我们一般的做法,例如说我们调用recv接收数据,在该函数返回之后,就代表我们已经接收好数据了。

异步IO

异步IO大概可以这样理解:

我们调用一个函数,在该函数返回之后其实该函数要完成的事情还没真正完成,而是被托管到其它地方了(如Nginx的事件驱动)。

可见该函数的功能并不是立刻完成的(但是最终会由托管的模块去完成)。

可能读者会有这样的疑问:异步IO到底是怎么样实现的呢?它有什么应用呢?下面将拿Nginx的事件驱动模型来解决这些问题。

异步非阻塞IO的应用

拿一个比较容易理解的例子:

在处理HTTP请求的时候,如果要忽略请求包体的内容(我们必须接收包体,但是不做处理),我们会ngx_discard_reqeust_body函数。

忽略请求包体的过程可能比较长,但是我们不需要理会包体的内容(该函数返回的内容我们并不在意),因此该函数是异步非阻塞的:

这样,在调用该函数之后我们可以继续执行下面的代码,而接收并忽略包体的动作则托管给事件驱动去完成。

异步非阻塞IO在Nginx的实现

Nginx的高并发来源于其异步非阻塞的事件驱动,下面将对Nginx基于epoll的事件驱动模型来说明。

关于epoll的使用方法跟Nginx事件驱动模型可以查看文章的前面两部分,这里将不做详细说明。

可见,Nginx主循环会调用ngx_epoll_process_events方法,而该方法则调用epoll_wait来获取事件并且处理事件。

我们只要调用epoll_ctl向epoll中添加或者删除事件(托管事件),Nginx事件驱动就会帮我们在事件准备好的时候处理相应的事件了。

上一篇 下一篇

猜你喜欢

热点阅读