Nginx篇06——Sendfile指令及其原理

2021-03-16  本文已影响0人  tinychen
image

nginx中http模块中的sendfile指令及其原理。

1、sendfile()介绍

nginx的http模块中有一个sendfile指令,默认是开启状态,官网的文档对其解释是:

Enables or disables the use of sendfile().

Starting from nginx 0.8.12 and FreeBSD 5.2.1, aio can be used to pre-load data for sendfile():

location /video/ {
    sendfile       on;
    tcp_nopush     on;
    aio            on;
}

In this configuration, sendfile() is called with the SF_NODISKIO flag which causes it not to block on disk I/O, but, instead, report back that the data are not in memory. nginx then initiates an asynchronous data load by reading one byte. On the first read, the FreeBSD kernel loads the first 128K bytes of a file into memory, although next reads will only load data in 16K chunks. This can be changed using the read_ahead directive.

简单来说就是启用sendfile()系统调用来替换read()和write()调用,减少系统上下文切换从而提高性能,当 nginx 是静态文件服务器时,能极大提高nginx的性能表现,而当 nginx 是反向代理服务器时,则没什么用了。下面我们来分析一下这个sendfile的工作原理:

2、原理分析

首先我们需要知道sendfile()和read()、write()之间最大的区别就是前者是属于系统调用,而后者是属于函数调用,我们来看下面这幅图

image

我们不难看出,nginx是属于Applicaiton的,而read()、write()属于函数调用,也就是在Lib Func这一层,sendfile()系统调用,位于System Call这一层,而想要对硬盘进行操作,是kernel才有的权限,上面的那些层都需要往下调用。

作为对比我们先来看一下正常情况下如果nginx调用read()和write()函数的操作过程:

我们都知道数据是存储在硬盘上面的,当数据被调用的时候会被加载进内存再被层层递进最后被CPU使用,这里个这个过程我们进行简化。

这里需要说明两点,一是用户态和内核态之间的切换是需要执行上下文切换操作的,这是十分耗费系统资源和时间的操作,二是因为read()、write()属于函数调用,它们是没有权限在kernel中操作,无法将data直接从Kernel Buffer(Hard Disk)传输到Kernel Buffer(Socket Engine)。

那么使用sendfile()呢?,由于是系统调用,所以在步骤二和步骤三的时候就可以不需要再将数据传输到User Buffer,直接在kernel中进行操作,省去了两次状态切换,也就是省去了两次的上下文切换,从而大幅度提升了性能。

我们来看一下下面的这幅图(灵魂画手上线→_→)

image

最后我们再来解释一下,为什么当 nginx 是反向代理服务器时,sendfile()就没什么用了呢。

顾名思义,sendfile()的作用是发送文件,也就是接收数据的一段是文件句柄,发送数据的那一端是socket。而在做反向代理服务器的时候,两端都是socket,此时无法使用sendfile(),也就不存在性能提升这一说了。

上一篇 下一篇

猜你喜欢

热点阅读