龙叔NGINX:nginx-性能调优/配置优化-相关指令

1,920 阅读19分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


引言

      默认的Nginx安装参数只能提供最基本的服务,还需要调整如网页缓存时间、连接超时、网页压缩等等相应参数,根据自身服务的特性,配置合适的参数,才能发挥出服务器的最大作用。

1·worker进程相关---合理使用服务器性能

1.1·worker_processes

每个 worker 进程都是单线程的进程,它们会调用各个模块以实现多种多样的功能。

如果这些模块确认不会出现阻塞式的调用,那么,有多少 CPU 内核就应该配置多少个进程;

反 之,如果有可能出现阻塞式调用,那么需要配置稍多一些的 worker 进程。

最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。

语法: worker_processes number

默认值: 1

示例: worker_processes 4;

查看linux服务器cpu个数,可以用来参考设置的值:cat /proc/cpuinfo |grep "cores"|uniq

1.2·worker_cpu_affinity

给工作进程绑定指定cpu,充分利用多核的性能优势

假定每一个 worker 进程都是非常繁忙 的 , 如果多个 worker 进程都在抢同一个 CPU , 那么这就会出现同步问题 。 反之 , 如果每一 个 worker 进程都独享一个 CPU , 就在内核的调度策略上实现了完全的并发。

一个进程是可以绑定多个cpu的

如:

2个CPU内核,2个进程,每个进程一个
worker_processes 2;
worker_cpu_affinity 01 10;

4个CPU内核,2个进程,每个进程两个
worker_processes 2;
worker_cpu_affinity 0101 1010;

4个CPU内核,4个进程,每个进程一个
worker_processes 4;
worker_cpu_affinity 1000 0100 0010 0001;

8个CUP内核,8个进程,每个进程一个
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

1.3 worker_connections

该 指令 用于 设置 每个 工作 进程 能够 处理 的 连接 数。

语法: worker_connections number

默认值:worker_connections 1024;

通过 worker_connections 和 worker_proceses( Nginx 工作 进程 数) 可以 计 算出 Nginx 服务器 能够 处理 的 最大 连接 数 max_clients, 计算 公式 如下:

      max_clients= worker_ proceses*worker_connections

假设 你 开启 了 8 个 Nginx 进程( worker_ proceses), 设置 的 worker_ connections 连接 数 为 32768, 那么 最大 连接 数 max_ clients 为 8* 32768 = 262144。 这 只是 理论 值, 实际 情况下, 受 操作系统、 文件 描述 符 与 端口 数 的 限制, 最大 连接 数 是 达不到 262144 的。

1.4·worker_priority

worker进程优先级设置,linux系统中,优先级高的进程会占用更多的系统资源,这里配置的是进程的静态优先级,取值范围 -20到+19,-20级别最高。因此可以把这个设置小一点,但不建议比内核进程的值低(通常为-5)

语法: worker_priority[-] number

默认值: on

示例: worker_priority -5;

1.5·worker_rlimit_nofile

该 指令 用于 指定 Nginx 进程 可以 打开 的 最大 文件 描述 符 数量。

配置成跟linux内核下文件打开数一致就可以了。可以通过ulimit -n 来查看

语法: worker_rlimit_nofile limit

示例: worker_rlimit_nofile 65535;

1.6·worker_rlimit_sigpending

该指令用于设置linux 2.6.6-mm2 版本之后的 linux 平台的事件信号队列长度上线

该指令主要影响事件驱动模型中rtsig 模型可以保存的最大信号数。Nginx 服务器的每一个工作进程有自己的事件信号队列用于存储客户端请求发生的信号,如果超过长度上限,nginx 服务器自动转用poll 模型处理未处理的客户端请求,为了保证Nginx 服务器对客户端请求的高效处理,需要根据实际的客户端并发请求数量和服务器运行环境能力设定该值。

语法: worker_rlimit_sigpending limit

示例: worker_rlimit_sigpending 32768;

2·coredump文件---保存故障线索

coredump是程序崩溃时的内存快照。
操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里。

2.1·worker_rlimit_core

该 指令 用于 指定 每个 Nginx 进程 的 最大 core 文件 大小。

worker_rlimit_core 10000m;

2.2·working_directory 指令

指定core文件的目录

语法: working_directory path

默认值:--prefix(该 指令 的 默认值 为 Nginx 使用 configure 文件 编译 安装 时, 参数-- prefix== PATH 指定 的 路径。)

案例:working_directory /usr/local/nginx/logs;

3·事件模型选择

use epoll;

linux建议epoll,FreeBSD建议采用kqueue,window下不指定。

补充说明:

与apache相类,nginx针对不同的操作系统,有不同的事件模型

A)标准事件模型

Select、poll属于标准事件模型,如果当前系统不存在更有效的方法,nginx会选择select或poll

B)高效事件模型

Kqueue:使用于FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X.使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。

Epoll:使用于Linux内核2.6版本及以后的系统。

/dev/poll:使用于Solaris 7 11/99+,HP/UX 11.22+ (eventport),IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+。

Eventport:使用于Solaris 10。 为了防止出现内核崩溃的问题, 有必要安装安全补丁。

4·超时设置---避免资源浪费

4.1·client_header_timeout

接收客户端header超时, 默认60s, 如果60s内没有收到完整的http包头, 返回408

语法: client_header_timeout time;
默认值: client_header_timeout 60s;
使用场景: http, server

4.2·client_body_timeout

接收客户端body超时, 默认60s, 如果连续的60s内没有收到客户端的1个字节, 返回408

语法: client_body_timeout time;
默认值: lient_body_timeout 60s;
使用场景: http, server, location

4.3·resolver_timeout

域名解析超时

语法: resolver_timeout time;
默认值: resolver_timeout 30s;
使用场景: http, server, location

4.4·send_timeout 

发送数据至客户端超时, 默认60s, 如果连续的60s内客户端没有收到1个字节, 连接关闭

语法: send_timeout time;
默认值: send_timeout 60s;
使用场景: http, server, location

4.5·proxy_connect_timeout 

nginx与upstream server的连接超时时间

语法: proxy_connect_timeout time;
默认值: proxy_connect_timeout 60s;
使用场景: http, server, location

4.6·proxy_read_timeout

nginx接收upstream server数据超时, 默认60s, 如果连续的60s内没有收到1个字节, 连接关闭

语法: proxy_read_timeout time;
默认值: proxy_read_timeout 60s;
使用场景: http, server, location

4.7·proxy_send_timeout

nginx发送数据至upstream server超时, 默认60s, 如果连续的60s内没有发送1个字节, 连接关闭

语法: proxy_send_timeout time;
默认值: proxy_send_timeout 60s;
使用场景: http, server, location

4.8·proxy_upstream_fail_timeout(fail_timeout)

Upstream模块下 server指令的参数,设置了某一个upstream后端失败了指定次数(max_fails)后,该后端不可操作的时间,默认为10秒

语法 server address [fail_timeout=30s]
默认值 10s
使用场景 upstream

5·长连接keepalive---避免频繁创建/销毁连接的开销

KeepAlive 在一段时间内保持打开状态,它们会在这段时间内占用资源。占用过多就会影响性能。

Nginx 使用 keepalive_timeout 来指定 KeepAlive 的超时时间(timeout)。指定每个 TCP 连接最多可以保持多长时间。Nginx 的默认值是 75 秒,有些浏览器最多只保持 60 秒,所以可以设定为 60 秒。若将它设置为 0,就禁止了 keepalive 连接。

nginx的长连接可以参考这篇文章,我觉得写的很好:segmentfault.com/a/119000002…

默认http1.1协议的请求头是默认开启keepalive,如图:

5.1·浏览器(client)到nginx的长连接

  http {
# 客户端连接的超时时间, 为 0 时禁用长连接,
keepalive_timeout 120s;
# 在一个长连接上可以服务的最大请求数目, 当达到最大请求数目且所有已有请求结束后, 连接被关闭, 默认为 100, 即每个连接的最大请求数
keepalive_request 10000;
}

5.1.1·keepalive_timeout

设置长连接超时事件

语法: keepalive_timeout timeout [header_timeout];

默认值: keepalive_timeout 75s;

使用场景: http, server, location

举例: keepalive_timeout 120s 120s;

  1. 第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接;
  2. 第二个参数:可选、在响应的header域中设置一个值“Keep-Alive: timeout=time”;通常可以不用设置

5.1.2·keepalive_request

keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。

默认是100。这个参数的真实含义,是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。

语法: keepalive_requests num;

默认值: keepalive_requests 100;

使用场景:http, server, location

举例:keepalive_requests 120;

5.2·从Nginx 到 Server(upstream) 的长连接

http {
upstream test{
server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s;
# 这个参数非常重要
keepalive 300
}
}

5.2.1·keepalive 

设置nginx 与后端服务器的长连接数量

语法:keepalive connections

默认值:无

使用场景:upstream 

connections参数设置每个worker进程与后端服务器保持连接的最大数量。这些保持的连接会被放入缓存,如果连接数大于这个值时,最久未被使用的连接会被关闭。

6·缓存---缓解服务器压力,节约带宽,提高响应速度,

配置合适的缓存可以提高浏览器的响应速度,尤其时一些静态文件的缓存,可以避免不必要的开销

这方面可以看我另一篇博客,这里就不再过多描述:nginx-缓存proxy_ cache和ngx_cache_purge_龙叔运维的博客-CSDN博客_nginx proxy_cache_purge

7.缓冲

如果没有缓冲,数据从代理的服务器发送并立即开始被发送到客户。

如果假定客户端很快,缓冲可以关闭而尽快使数据到客户端。

有了缓冲,Nginx代理将暂时存储后端的响应,然后按需供给数据给客户端。如果客户端是缓慢的,允许Nginx服务器关闭到后端的连接。然后,它可以处理数据分配到客户端,以任何可能的速度。

Nginx默认有缓冲设计,因为客户端往往有很大的不同的连接速度。我们可以用以下指令调节缓冲行为。可以在HTTP,server或location位置来设置

最有用的调整是proxy_buffers和proxy_buffer_size指令。

案例:

proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;#设定缓存文件夹大小,大于这个值,将从upstream服务器传

7.1·proxy_buffering

该指令控制缓冲是否启用。默认情况下,它的值是“on”。

语法:proxy_buffering on|off
默认值:proxy_buffering on
使用场景:http,server,location

7.2·proxy_buffers 

该指令设置缓冲区的大小和数量,从被代理的后端服务器取得的响应内容,会放置到这里. 默认情况下,一个缓冲区的大小等于内存页面大小,可能是4K也可能是8K,这取决于平台。

语法:proxy_buffers  数量  大小
默认值:proxy_buffers 8  4k/8k
使用场景:http,server,location

7.3·proxy_buffer_size

从后端服务器的响应头缓冲区大小,它包含headers,和其他部分响应是分开的。该指令设置响应部分的缓冲区大小。默认情况下,它和proxy_buffers是相同的尺寸,但因为这是用于头信息,这通常可以设置为一个较低的值。

语法:proxy_buffer_size  the size
默认值:proxy_buffer_size 4k/8k
使用场景:http,server,location

7.4·proxy_busy_buffers_size

此指令设置标注“client-ready”缓冲区的最大尺寸。而客户端可以一次读取来自一个缓冲区的数据,缓冲被放置在队列中,批量发送到客户端。此指令控制允许是在这种状态下的缓冲空间的大小。

语法:proxy_busy_buffers_size                大小
默认值:proxy_busy_buffers_size  proxy_buffer_size*2
使用场景:http,server,location,if

7.5·proxy_max_temp_file_size

非buffer独有指令,这是每个请求能用磁盘上临时文件最大大小。这些当上游响应太大不能装配到缓冲区时被创建。

指定当响应内容大于proxy_buffers指定的缓冲区时, 写入硬盘的临时文件的大小. 如果超过了这个值, Nginx将与Proxy服务器同步的传递内容, 而不再缓冲到硬盘. 设置为0时, 则直接关闭硬盘缓冲.

举例:

proxy_max_temp_file_size 0;

7.6·proxy_temp_file_write_size

非buffer独有指令,这是当被代理服务器的响应过大时Nginx一次性写入临时文件的数据量。默认是proxy_buffer_size和proxy_buffers中设置的缓冲区大小的2倍,Linux下一般是8k。

举例:

proxy_temp_file_write_size 64k;

7.7·proxy_temp_path

非buffer独有指令,当上游服务器的响应过大不能存储到配置的缓冲区域时,Nginx存储临时文件硬盘路径。

语法: proxy_temp_path path [level1 [level2 [level3]]];

使用 环境: http, server, location

7.8·buffer 工作原理

引用自 nginx 缓冲区设置 proxy_buffers - 左岸丶 - 博客园

  1. 所有的proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。\
  2. proxy_buffering 是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。\
  3. 无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。\
  4. 在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们 被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的 话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer 传输完了会从temp_file里面接着读数据,直到传输完毕。\
  5. 一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处 在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户 端的buffer数量的。

8·gzip---节约带宽,提高响应速度

Nginx开启Gzip压缩功能,将响应报⽂发送⾄客户端之前可以启⽤压缩功能,这能够有效地节约带宽,并提⾼响应⾄客户端的速度。Gzip压缩可以配置http,server和location模块下。

可以使网站的css、js 、xml、html 文件在传输时进行压缩,提高访问速度, 进而优化Nginx性能!  Web网站上的图片,视频等其它多媒体文件以及大文件,因为压缩效果不好,所以对于图片没有必要支压缩,如果想要优化,可以图片的生命周期设置长一点,让客户端来缓存。

案例:

gzip on; ``#开启gzip压缩功能

gzip_min_length 10k; ``#设置允许压缩的页面最小字节数; 这里表示如果文件小于10个字节,就不用压缩,因为没有意义,本来就很小.

gzip_buffers 4 16k; ``#设置压缩缓冲区大小,此处设置为4个16K内存作为压缩结果流缓存

gzip_http_version 1.1; ``#压缩版本

gzip_comp_level 2; ``#设置压缩比率,最小为1,处理速度快,传输速度慢;9为最大压缩比,处理速度慢,传输速度快; 这里表示压缩级别,可以是0到9中的任一个,级别越高,压缩就越小,节省了带宽资源,但同时也消耗CPU资源,所以一般折中为6

gzip_``types text``/css text``/xml application``/javascript``; ``#制定压缩的类型,线上配置时尽可能配置多的压缩类型!

gzip_disable ``"MSIE [1-6]."``; ``#配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)

gzip vary on; ``#选择支持vary header;改选项可以让前端的缓存服务器缓存经过gzip压缩的页面; 这个可以不写,表示在传送数据时,给客户端说明我使用了gzip压缩

8.1·gzip

该 指令 用于 开启 或 关闭 gzip 模块。

语法: gzip on| off 

默认值: gzip off

使用 环境: http, server, location, if (x) location

8.2·gzip_buffers

设置 系统 获取 几个 单位 的 缓存 用于 存储 gzip 的 压缩 结果 数据 流。 例如 4 4k 代表 以 4k 为 单位, 按照 原始 数据 大小 以 4k 为 单位的 4 倍 申请 内存。 4 8k 代表 以 8k 为 单位, 按照 原始 数据 大小 以 8k 为 单位 的 4 倍 申请 内存。 如果 没有 设置, 默认值 是 申请 跟 原始 数据 相同 大小 的 内存 空间 去 存储 gzip 压缩 结果。

语法: gzip_buffers number size

默认值: gzip_buffers 4 4k/8k

使用 环境: http, server, location

8.3·gzip_comp_level

gzip 压缩 比, 1 压缩 比 最小 处理 速度 最快, 9 压缩 比 最大 但 处理 速度 最慢( 传输 快 但 比较 消耗 cpu)。

语法: gzip_comp_level 1.. 9 

默认值: zip_comp_level 1

使用 环境: http, server, location

8.4·gzip_min_length

设置 允许 压缩 的 页面 最小 字节数, 页面 字节数 从 header 头 的 Content- Length 中进 行 获取。 默认值 是 0, 不管 页面 多大 都 压缩。 建议 设置 成 大于 1k 的 字节数, 小于 1k 可能 会 越 压 越大。 即: gzip_ min_ length 1024。

语法: gzip_min_length length

默认值: gzip_min_length 0

使用 环境: http, server, location

8.5·gzip_http_version

识别 http 的 协议 版本。

语法: gzip_http_version 1. 0| 1. 1

默认值: gzip_http_version 1. 1

使用 环境: http, server, location

8.6·gzip_ proxied

语法: gzip_proxied [ off| expired| no- cache| no- store| private| no_ last_ modified| no_ etag| auth| any]...

默认值: gzip_proxied off

使用 环境: http, server, location

Nginx 作为 反向 代理 的 时候 启用, 开启 或 关闭 后端 服务器 返回 的 结果, 匹配 的 前提 是 后端 服务器 必须 要 返回 包含“ Via” 的header 头。

off—— 关闭 所有 的 代理 结果 数据 的 压缩。

expired—— 启用 压缩, 如果 header 头中 包含“ Expires” 头 信息。

no-cache—— 启用 压缩, 如果 header 头中 包含“ Cache- Control: no- cache” 头 信息。

no-store—— 启用 压缩, 如果 header 头中 包含“ Cache- Control: no- store” 头 信息。

private—— 启用 压缩, 如果 header 头中 包含“ Cache- Control: private” 头 信息。

no_last_ modified—— 启用 压缩, 如果 header 头中 不 包含“ Last- Modified” 头 信息。

no_etag—— 启用 压缩, 如果 header 头中 不 包含“ ETag” 头 信息。

auth—— 启用 压缩, 如果 header 头中 包含“ Authorization” 头 信息。

any—— 无条件 启用 压缩。

8.7·gzip_types

匹配 mime 类型 进行 压缩,( 无论 是否 指定)“ text/ html” 类型 总是 会被 压缩 的。

语法: gzip_types mime-type[ mime-type...]

默认值: gzip_ types text/ html

使用 环境: http, server, location

9·高效文件传输模式

参数sendfile on 用于开启文件高效传输模式,同时将tcp_nopush on 和tcp_nodelay on 两个指令设置为on,可防止网络及磁盘I/O阻塞,提升Nginx工作效率

对于普通应用设为 on(开启),如果用来进行下载等应用磁盘IO重负载应用,可设置为off(关闭),以平衡磁盘与网络I/O处理速度,降低系统的负载。

案例:

sendfile on; # 开启文件的高效传输模式

tcp_nopush on; # 激活 TCP_CORK socket 选择

tcp_nodelay on; #数据在传输的过程中不进缓存

9.1·sendfile

用于开启文件的高效传输模式,该参数实际上是激活了 sendfile() 功能,sendfile() 是作用于两个文件描述符之间的数据拷贝函数,这个拷贝操作是在内核之中的,被称为 "零拷贝" ,sendfile() 比 read 和 write 函数要高效得多,因为 read 和 write 函数要把数据拷贝到应用层再进行操作

同时将tcp_nopush on 和tcp_nodelay on 两个指令设置为on,可防止网络及磁盘I/O阻塞,提升Nginx工作效率;注意:如果图片显示不正常把这个改成off

语法: sendfile on | off;

使用环境: http,server,location,if in location

看一下用 sendfile() 来进行网络传输的过程:

sendfile(socket, file, len);

硬盘 >> kernel buffer (快速拷贝到kernel socket buffer) >> 协议栈

1、系统调用 sendfile() 通过 DMA 把硬盘数据拷贝到 kernel buffer,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有 user mode 和 kernel mode 之间的切换,在 kernel 中直接完成了从一个 buffer 到另一个 buffer 的拷贝。

2、DMA 把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从 user mode 拷贝到 kernel mode,因为数据就在 kernel 里。

9.2·tcp_nopush

用于激活 Linux 上的 TCP_CORK socket 选项,此选项仅仅当开启 sendfile 时才生效,防止网路阻塞,tcp_nopush 参数可以允许把 http response header 和文件的开始部分放在一个文件里发布,以减少网络报文段的数量(将响应头和正文的开始部分一起发送,而不一个接一个的发送)

 语法:tcp_nopush on | off;

 使用环境:http,server,location

9.3·tcp_nodelay

该参数决定是否关闭nagle。

nagle算法最核心的功能,就是把小包组成成大包,提高带宽利用率,

终端应用程序每产生一次操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞。

为了避免这种情况,TCP堆栈实现了等待数据 0.2秒钟,因此操作后它不会发送一个数据包,而是将这段时间内的数据打成一个大的包。

这一机制是由Nagle算法保证。

tcp_nodelay on;就是禁用了Nagle 算法。

● nginx中是否打开nagle算法,要取决于业务场景:
(1)tcp_nodelay off,会增加通信的延时,但是会提高带宽利用率。在高延时、数据量大的通信场景中应该会有不错的效果
(2)tcp_nodelay on,会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果