nginx

发布于
server

什么是反向代理?

sendfile

Linux kernel 2.1 前,读写数据基本都是用 read 和 write 系调用

以 nginx 来说如果一个请求建立,从磁盘的文件到网络连接之间会通过硬件(DMA)— 内核层 — 用户层多次读写来完成文件数据的复制传输

从内核层用 read 系统调用读到用户层,再从用户层用 write 系统调用写到内核层,每一次用户层到内核层的进行一次上下文转换,这种代价是非常昂贵的。甚至在没有数据变化时这种复制尤其显得多余

1、调用 read 函数,文件数据被 copy 到内核缓冲区

2、read 函数返回,文件数据从内核缓冲区 copy 到用户缓冲区

3、write 函数调用,将文件数据从用户缓冲区 copy 到内核与 socket 相关的缓冲区

4、数据从 socket 缓冲区 copy 到相关协议引擎

硬盘 —> 内核 buf—> 用户 buf—>socket 相关缓冲区 —> 协议引擎

文件数据实际上是经过了四次 copy 操作

大量并发,系统调用非常频繁,服务器的性能就会下降


linux kernel 2.1 引进 sendfile

1、sendfile 系统调用,文件数据被 copy 至内核缓冲区

2、再从内核缓冲区 copy 至内核中 socket 缓冲区

3、最后再 socket 缓冲区 copy 到协议引擎

相较传统 read/write 方式,sendfile 已经减少了内核缓冲区到 user 缓冲区,再由 user 缓冲区到 socket 缓冲区的文件 copy

而 linux kernel 2.4 之后,sendfile 实现了更简单的方式,系统调用方式仍然一样,当文件数据被复制到内核缓冲区时,不再将所有数据 copy 到 socket 缓冲区,仅将记录数据位置和长度相关的数据保存到 socket 相关的缓存,实际数据由 DMA 模块直接发送到协议引擎,再次减少了一次 copy 操作

senfile 需要输入的文件描述符是一个支持 mmap 的真实文件或者设备,socket 就不能作为输入的 fd,而输出的 fd 是可以的


location / {
aio on;
directio 512k;
sendfile on;
output_buffers 1 128k;
...

请求的文件> 512k,启用 directio,从而 aio 生效,进而 sendfile 不生效

请求的文件< 512k,禁用 directio,从而 aio 也就不生效,转而使用 sendfile ()

对大文件用 aio,节省 cpu,而对小文件用 sendfile,减少拷贝

且对于大文件 aio 用 directio,避免挤占文件系统缓存,让文件系统缓存更多的小文件。 从理论上来看,这种配置比较适合系统内存有限、小文件请求比较多、间隔有几个大文件请求的 Web 环境

如果内存足够大,那么应该充分利用文件系统缓存,而 directio 使得 aio 无法使用缓存是衡量最终是否需要采用 aio 的一个需要仔细考虑的因素


location /video/ {
sendfile on;
sendfile_max_chunk 256k; 
aio threads;
directio 512k;
output_buffers 1 128k;
}

启用 aio 时会自动启用 directio

小于 directio 定义的大小的文件则用 sendfile 进行发送,超过或等于 directio 定义的大小的文件,将采用 aio 线程池进行发送

也就是说 aio 和 directio 适合大文件下载,因为大文件不适合进入操作系统的 buffers/cache, 浪费内存,而且 Linux AIO 也要求使用 directio 的形式

sendfile maxChunk 可以减少阻塞调用 sendfile () 所花费的最长时间,Nginx 不会尝试一次将整个文件发送出去,而是每次发送大小为 256KB 的块数据

nginx 1.7.11 为 AIO 引入线程池,能用多线程读取和发送文件,以免worker进程被阻塞。–with-threads 选项