Nginx性能调优

时间:2020-03-21 11:47:38  来源:igfitidea点击:

Nginx是一个众所周知的Web服务器,并且已被业界的许多主要参与者所采用。
其快速采用的主要原因是,与其他Web服务器(如Apache)相比,它是如此之快。
基本上,nginx用于解决称为c10k的问题。
对于许多人来说,它的性能要比市场上任何其他Web服务器都要好得多。
在本文中,我们将看到如何修改nginx配置以增强它或者说出性能调整nginx。

我们稍后再进入配置部分,因为有很多概念需要首先理解。

C10k是指优化网络连接的方法,以便它可以同时处理一万个范围内的连接。

Apache在阻塞I/O模型中工作。
用外行术语来说,这意味着发出读/写请求时,它将阻止其他请求,直到该请求完成为止。
解决此问题的最佳方法是为每个连接创建单独的线程/进程。
这就是Apache所做的。

Apache通过对每个客户端使用专用线程来阻止I/O来工作。

尽管Apache的每个连接/请求专用线程是服务客户端的一种好方法,但它既消耗内存,也消耗处理器。

它的处理器很费力,因为对于每个命中Apache服务器的请求,服务器处理器必须在不同的进程之间进行切换(因为每个http请求的连接都会创建一个新的进程/线程)

现在,如果我们根本不关心性能和资源利用率,那么可以使用Apache Web服务器来处理请求,从而继续使用Apache每个连接模型的线程。
但是,如果我们同时关注资源利用率和性能,那么事件驱动架构的nginx模型是最好的选择。

Nginx使用单线程非阻塞I/O机制来处理请求。
由于它使用非阻塞I/O,因此一个进程可以处理太多的连接请求。

由于所有内容都是linux中的文件,因此即使网络连接也是内部文件。
每个进程都有其自己的文件描述符集,需要经常对其进行轮询,以识别哪个是准备读取或者写入的文件描述符(nginx服务器接收的连接甚至都由nginx进程以文件形式维护。
连接生命周期的描述符)。

如前所述,nginx使用具有单线程的非阻塞I/O。
因此,单个过程必须标识准备好读取或者写入哪个连接文件。
为此,操作系统具有三种不同的方法。
它们在下面提到。

  • select方法
  • Poll方法
  • Epoll方法

同时使用select和poll并不是识别已准备好哪个文件描述符的有效方法。
因为这两种方法在功能上是相同的(不足以向我们解释select和epoll之间的区别,所以如果我们是程序员,我建议我们通过下面的链接来了解有关select和poll的更多信息。

因此,nginx可以使用select或者poll方法来确定准备读取或者写入哪个文件(文件描述符)。
但是,当连接数量过多时,这两种方法都不够高效。
例如,如果我们想一次服务10000个连接。
并且其中只有一个可以读取。
为了识别准备读取的一个文件描述符,该过程仍必须扫描其余9999个文件描述符(这是浪费资源)。

除了select和Poll之外,另一种方法也称为epoll来进行救援。
仅在2.6以后的Linux内核中可用。
与轮询和选择相比,Epoll使用了一种有效的机制。

如果与服务器建立了10000个连接,其中8000个为空闲连接。
使用轮询和选择效率不高,因为epoll仅会重视活动的连接。
请注意,这三个选择,轮询和epoll基本上都具有相同的作用,但是当必须服务数千个连接时,使用epoll的CPU占用较少。

我们可以修改nginx配置文件以使用epoll,如下所示。
如果我们使用的是centos,则此nginx配置文件将位于/etc/nginx/nginx.conf。
这是在配置文件中的事件块内完成的。

events {
    use epoll;
}

现在,如前所述,nginx在非阻塞单流程模型上工作。
尽管我们说的是单个进程,但是我们可以要求Nginx启动多个工作进程。
基本上就像我们有两个工作进程一样,每个工作进程将处理所有请求。
通常根据系统上具有的CPU内核数来配置此设置。
我们可以使用以下任一命令找到系统上CPU内核的数量。

[root@www ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8

cat /proc/cpuinfo

我非常确定,如果我们在生产服务器上,将拥有多个cpu内核。
从lscpu命令输出中可以看到,我有8个处理器,因此我将要求nginx启动将处理请求的8个工作进程。

worker_processes  8;

另外,我们也可以配置nginx来确定服务器上的内核数,并相应地启动工作进程。
可以通过如下方式将worker_processes修改为auto来完成。

worker_processes  auto;

我们可以在nginx中修改的另一个重要因素是我们的工作进程可以打开的最大文件数。
如前所述,每个连接都是通过创建文件来识别它们的方式进行处理的。
因此,允许创建的文件数量更多,工作人员可以使用更多连接。

可以在nginx中修改一个配置值以完成此操作。
如果服务器的流量非常大,最好将此值设置为较高的值。

worker_rlimit_nofile 100000;

即使我将我的nginx.conf中的worker_process设置为8或者自动,它也会最终启动8个工作进程。
所有这8个过程都准备好为连接服务。
但是,我们可以进一步优化这些工作进程,以使其与服务器建立尽可能多的连接。

我们可以定义单个工作进程可以同时服务的最大连接数。
如果未指定,则默认为512个连接。
但是我们可以修改此设置以接受每个工作人员更多的连接。
可以如下所示进行。

events {
    use epoll;
    worker_connections 1024;
}

我们还需要将我们的工作进程配置为一次接受多个连接。
这可以通过修改事件块来完成,如下所示。

events {
    use epoll;
    worker_connections 2048;
    multi_accept on
}

完成上述更改后,我们的最终配置必须类似于以下内容。

worker_processes auto;
worker_rlimit_nofile 100000;
events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

因此,现在我的Nginx Web服务器已准备就绪,可以一次提供大约8192个连接(8个工作进程* 1024个连接)。

请注意,我们已经在nginx中使用事件模块来修改工作程序连接,使用epoll方法和multi_accept。
这就是为什么它们位于配置文件中的事件块(事件{})内的原因。
还有另一个名为http的模块,这是我们将用来定义与http相关的内容的主要模块。

现在,我们将在http模块内修改并添加一些参数,以更快地提高nginx的速度。

任何Web服务器的主要功能之一就是日志记录。
日志记录将为服务器管理员提供正在处理的请求类型的详细信息,还有助于进行故障排除。
Web服务器日志也可以用于进行Web分析,因为日志文件包含请求的完整详细信息。
这些详细信息包括请求的源地址,用户代理(客户端使用的浏览器),请求中请求的资源(或者访问的URL),目标地址,引荐网址等。

尽管日志记录是一项重要且必不可少的功能,但它会在磁盘上执行很多I/O操作。
请不要忘记这样一个事实,即每个请求在到达服务器并得到服务后便会立即记录下来。

这意味着,对于每个请求,Web服务器都必须处理日志并将相关详细信息添加到日志文件中(这将增加处理量和I/O使用率。
)。
如果我们托管的访问量过多,则请确保Web服务器记录日志的时间确实很糟糕。

因此,完全关闭Web服务器上的日志可以节省大量I/O以及CPU能力。
当我们拥有一个高流量的时,这变得非常方便。
在nginx中,我们可以通过以下选项完全打开日志记录。

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    access_log off;
}

上面的http块中显示的access_log off选项告诉我们不要记录服务器正在处理的请求。

当我们使用Web浏览器访问时,真正发生的是浏览器与目标服务器建立了HTTP连接。
真正的开销是开始。
这意味着建立连接是主要的耗时(尽管以秒为单位,但考虑性能时却很重要)。

让我们举个例子,我们正在访问一个新闻相关的,并且正在浏览该上的不同URL,以快速浏览不同新闻内容。
想象一下一种情况,客户端浏览器必须为我们在站点上访问的每个URL建立到服务器的新http连接。
对于站点访问者而言,这将有点慢。
因为访问每个URL都有另一个首先建立HTTP连接的开销。

HTTP 1.0版实现了一项称为“保持活动连接”的功能,以解决为每个请求创建连接的开销。
但是,有一个超时时间。
简而言之,Web服务器允许我们指定使连接保持活动状态的超时时间,因此在该间隔内建立的连接不需要创建连接。

简而言之,连接保持活动直到我们指定的保持活动超时

并且相信与其他任何Web服务器相比,nginx在处理大量活动连接方面要好得多。
它声称仅使用2.5 MB内存就可以处理多达10000个活动连接。
因此,如果我们使用的是nginx,请继续将活着的值提高到65以上。

keepalive_timeout  65;

如果我们是Linux用户,请确保我们一定听说过gzip压缩。
我们可能已经知道使用gzip压缩文本内容可以达到的压缩级别。
我们得到的压缩率在90的范围内。
这是一个非常棒的压缩级别。

网页的主要部分始终是文本内容。
使网页看起来不错并增强其功能的组件也是文本内容。
尽管它们都是以不同语言编写的代码,例如html,CSS甚至是JavaScript(浏览器知道会解释这些语言),但它们都是文本内容。

通过有线方式将所有数据发送到客户端总是有点慢。
因此,每台Web服务器都支持压缩机制,以压缩发送到客户端的数据。
同样,所有现代网络浏览器都知道如何解压缩它。

启用压缩对网络访问速度较慢的用户非常有帮助。
启用压缩并不是一项艰巨的任务。
与先前显示的选项类似,在nginx.conf文件的http块部分中启用了压缩和gzip选项。

如果我们在Linux中使用gzip工具完成了压缩,那么我们必须知道根据大小来压缩内容需要一点时间。
而且我们可能还知道,如果增加压缩级别,最终结果并不会有太大的实质性差异,但是这会花费更多的时间,并且会占用更多的CPU使用率。

类似地,在我们的nginx Web服务器上配置压缩时,我们需要特别注意压缩内容,压缩时间以及压缩级别。
此外,我们还需要一种机制,可以针对不支持此功能的旧版Web浏览器禁用压缩。

因此,第一步是启用压缩。
这可以通过在http块内添加以下参数来完成。

gzip on;

第二步是告诉nginx仅在发送的数据大小超出我们指定的限制时进行压缩。
可以如下所示进行。

gzip_min_length 256;

nginx官方以一种很好的方式描述了上述最小长度参数。
以下是官方nginx http模块部分中对min length参数的描述。

小于此字节长度的响应将不会被压缩。
长度由“ Content-Length”标题确定。

现在,正如我们前面所讨论的,过多的压缩不会带来实质性的改变,而只会增加CPU使用率。
压缩级别是从1到9的比例。
我们确实需要压缩,但是不需要更高级别。
因为即使是基本的gzip压缩也做得很好。
因此,让压缩级别的值保持在3到5之间(取决于意愿)

gzip_comp_level 3;

现在,我们需要告诉我们的Nginx Web服务器有关需要压缩的数据类型。
这通常是文本内容,范围从rss,css,html,javascript等。
可以通过添加以下行来完成。

gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

因此,我们最后的http块部分将类似于以下所示。

http {
include       /etc/nginx/mime.types;
default_type  application/octet-stream;
access_log off;
keepalive_timeout  65;
gzip on;
gzip_min_length 256;

gzip_comp_level 3;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}

Nginx可以大大提高性能的另一个方面是启用元数据缓存。
请注意,这不会启用内容缓存,而是启用元数据缓存。
Nginx的这一功能(又是http块部分的一部分)被称为Open_file_cache。
首先要做的就是启用它。

open_file_cache max=10000 inactive=30s;

请注意,没有用于此的ON开关,但是有一个OFF开关。
在理解上述配置参数之前,让我们看一下将要缓存的内容是什么。

  • 打开文件描述符
  • 文件描述符修改时间,大小等
  • 错误状态,例如没有权限,没有文件等

第一个参数max = 10000告诉nginx Web服务器仅缓存这么多条目。
旧的非活动条目将自动清除。
请注意,非活动开关会告知我们一个时间,如果不活动,它将在该时间之后删除缓存条目。

下面提到了其他需要配置的open_file_cache选项。

  • 缓存条目的有效性(open_file_cache_valid)。
  • 在不活动的秒数之前必须访问高速缓存条目的最小次数,以便它保留在高速缓存中(open_file_cache_min_uses)
  • 搜索文件时缓存错误(open_file_cache_errors)

因此,我们的打开文件缓存配置将如下所示。

open_file_cache max=10000 inactive=30s;
open_file_cache_valid    60s;
open_file_cache_min_uses 2;
open_file_cache_errors   on;

如果访问量很大,并且使用nginx,则正确设置上述打开文件缓存参数可以真正提高性能。

尽管我们确实在nginx中看到了keep alive的内容,但是还有很少的参数对于指定要从客户端保持活动的连接数非常有帮助。
另外,当客户端不响应时,我们还有其他一些选项可以关闭连接。

第一个是限制可以通过保持活动连接进行服务的请求总数。
如果未提及,则默认值为100(这意味着客户端可以在一个保持活动的连接中发出100个成功的请求。
)。
即使对于一个客户来说这太高了,如果我们愿意,也可以将该值增加到200左右。
可以如下所示进行。

keepalive_requests 200;

为没有响应的客户端保持连接开放不是一个好主意,关闭连接并释放与之关联的内存总是更好。
可以如下所示进行。

reset_timedout_connection on;

需要启用更快的tcp数据传输的另一个不错的选择是sendfile。
techrepublic上有一篇很棒的文章,详细解释了整个内容。

可以在nginx中启用此选项,如下所示。

sendfile on;
tcp_nopush on;

tcp_nopush选项将使nginx以单个数据包而不是单独的数据包发送所有头文件。

因此,我们最终的nginx.conf文件将类似于下图所示。

worker_processes  auto;
worker_rlimit_nofile 100000;
events {
    use epoll;
    worker_connections 1024;
    multi_accept on    
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    access_log off;
    keepalive_timeout  65;
    keepalive_requests 200;
    reset_timedout_connection on;
    sendfile on;
    tcp_nopush on;
    gzip on;
    gzip_min_length 256;
    gzip_comp_level 3;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    open_file_cache max=10000 inactive=30s;
    open_file_cache_valid    60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors   on;
}

一旦配置了所需的更改以提高速度,我建议使用AB工具或者任何其他工具进行Web服务器性能测试,以确认其用途。