聊聊Nginx参数的优化_最大连接数

工作上,需要配置 Nginx,要投入生产使用,做了一点优化工作,故记下一些优化工作。

 

优化 Nginx 进程数量worker_process指令


配置参数如下:

worker_processes 1; # 指定 Nginx 要开启的进程数,结尾的数字就是进程的个数,可以为 auto

这个参数调整的是 Nginx 服务的 worker 进程数,Nginx 有 Master 进程和 worker 进程之分,Master 为管理进程、真正接待“顾客”的是 worker 进程。

进程个数的策略:worker 进程数可以设置为等于 CPU 的核数。高流量高并发场合也可以考虑将进程数提高至 CPU 核数 x 2。这个参数除了要和 CPU 核数匹配之外,也与硬盘存储的数据及系统的负载有关,设置为 CPU 核数是个好的起始配置,也是官方建议的。(为了让多核CPU更好的并行处理任务,我们可以将worker_processes指令的赋值适当的增大一些,最好赋值为机器CPU的倍数。当然这个值也不是越大越好,Nginx进程太多可能增加主进程调度负担,也可能影响系统的I/O效率。针对双核CPU,建议设置为2或4,如果你的机器是四核CPU,可以设置为worker_processes 4)

当然,如果想省麻烦也可以配置为​​worker_processes auto;​​,将由 Nginx 自行决定 worker 数量。当访问量快速增加时,Nginx 就会临时 fork 新进程来缩短系统的瞬时开销和降低服务的时间。

 

worker_cpu_affinity将不同的进程绑定到不同的CPU


默认情况下,Nginx 的多个进程有可能运行在同一个 CPU 核上,导致 Nginx 进程使用硬件的资源不均,这就需要制定进程分配到指定的 CPU 核上处理,达到充分有效利用硬件的目的。配置参数如下:

worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;

其中 ​​worker_cpu_affinity​​​ 就是配置 Nginx 进程与 CPU 亲和力的参数,即把不同的进程分给不同的 CPU 核处理。这里的​​0001 0010 0100 1000​​是掩码,分别代表第1、2、3、4核CPU。上述配置会为每个进程分配一核CPU处理。

当然,如果想省麻烦也可以配置​​worker_cpu_affinity auto;​​将由 Nginx 按需自动分配。

优点:提升CPU缓存的命中率,
context switch:会产生CPU的不必要的消耗;cpu进程切换(浪费cpu资源和时间)
CPU隔离:worker线程绑定单个cpu

 

worker_priority number 设置Worker进程的静态优先级


Syntax: worker_priority number;
Default: worker_priority 0;
Context: main

指明worker进程的nice值 -20-19,在Nginx的worker配置上面会将worker优先级配置到最高级别,比如-19。这样静态优先级高那么操作系统往往给其分配的时间片比较大,这样Nginx才能比较好的在用户态完成请求的切换使用CPU少做无用功,减少请求切换能够使得Nginx性能更高。

 

配置 worker 进程的最大打开文件数


调整配置 Nginx worker 进程的最大打开文件数,这个控制连接数的参数为​​ worker_rlimit_nofile​​。该参数的实际配置如下:

#配置Nginx worker进程最大打开文件数
worker_rlimit_nofile 65535;

可设置为系统优化后的 ​​ulimit -HSn​​ 的结果

 

Nginx 事件处理模型优化


Nginx 的连接处理机制在不同的操作系统中会采用不同的 I/O 模型,在 linux 下,Nginx 使用 epoll 的 I/O 多路复用模型,在 Freebsd 中使用 kqueue 的 I/O 多路复用模型,在 Solaris 中使用 /dev/poll 方式的 I/O 多路复用模型,在 Windows 中使用 icop,等等。配置如下:

events {
use epoll;
}

​events​​​ 指令是设定 Nginx 的工作模式及连接数上限。​​use​​指令用来指定 Nginx 的工作模式。Nginx 支持的工作模式有 select、 poll、 kqueue、 epoll 、 rtsig 和/ dev/poll。当然,也可以不指定事件处理模型,Nginx 会自动选择最佳的事件处理模型。

 

 

单个进程允许的客户端最大连接数


Linux默认值open files和max user processes为1024

ulimit -n

1024

ulimit Cu

1024

问题描述:

说明server只允许同时打开1024个文件,处理1024个用户进程
使用ulimit -a可以查看当前系统饿所有限制值,使用ulimit -n可以查看当前的最大打开文件数
新装的linux默认只有1024,当作负载较大的服务器时
容易遇到erro:too many open files
需要将其改大

解决方法:

使用ulimit Cn 65535可以及时修改,但重启后就无效了。
(ulimit -SHn 65535等效ulimit -n 65535,-S,soft,-H,hard)

有三种修改方式:

  1. 在/etc/rc.local中增加一行 ulimit -SHn 65535
  2. 在/etc/profile中增加一行 ulimit -SHn 65535
  3. 在/etc/security/limits.conf 最后增加
    *soft nofile 65535
    *hard nofile 65535
    *soft nproc 65535
    *hard nproc 65535
    具体使用哪种,在 CentOS 中使用第1 种方式无效果,使用第3 种方式有效果
    而在Debian 中使用第2 种有效果

ulimit -n

65535

ulimit -u

65535

备注:ulimit 命令本身就有分软硬设置,加-H 就是硬,加-S 就是软默认显示的是软限制

soft 限制指的是当前系统生效的设置值。 hard 限制值可以被普通用户降低。但是不能增加。 soft 限制不能设置的比 hard 限制更高。 只有 root 用户才能够增加 hard 限制值。

 

基础背景:

Nginx 是多进程模型,Worker 进程用于处理请求。

单个进程的连接数(文件描述符 fd),有上限(nofile):ulimit -n。

Nginx 上配置单个 Worker 进程的最大连接数:worker_connections 上限为 nofile。

Nginx 上配置 Worker 进程的数量:worker_processes。

因此,Nginx 的最大连接数:

Nginx 的最大连接数:Worker 进程数量 x 单个 Worker 进程的最大连接数。

上面是 Nginx 作为通用服务器时,最大的连接数。

Nginx 作为反向代理服务器时,能够服务的最大连接数:(Worker 进程数量 x 单个 Worker 进程的最大连接数)/ 2。

Nginx 反向代理时,会建立 Client 的连接和后端 Web Server 的连接,占用 2 个连接。

在使用nginx服务器的过程当中,遇到无法访问nginx服务器的情况,查看日志一直报如下错误:

聊聊Nginx参数的优化_xml_02

根据报错信息,可以推测nginx服务器最大的访问连接数设置小了,此指令设置的就是Nginx服务器能接收的最大访问量,其中包括前端用户也包括其他连接,这个值理论上等于此指令的值和允许开启的工作进程最大数的乘积。此指令一般设置为65535:

 #单个进程允许的客户端最大连接数
worker connections 65535;

另外,进程的最大连接数受 Linux 系统进程的最大打开文件数限制,在执行操作系统命令 ​ulimit -HSn 65535​​或配置相应文件后, ​​worker_connections​​ 的设置才能生效。

 

 

配置获取更多连接数


multi_accept

multi_accept可以让nginx worker进程尽可能多地接受请求。它的作用是让worker进程一次性地接受监听队列里的所有请求,然后处理。如果multi_accept的值设为off,那么worker进程必须一个一个地接受监听队列里的请求。

events {
multi_accept on;
}

默认Nginx没有开启multi_accept。

如果web服务器面对的是一个持续的请求流,那么启用multi_accept可能会造成worker进程一次接受的请求大于worker_connections指定可以接受的请求数。这就是overflow,这个overflow会造成性能损失,overflow这部分的请求不会受到处理。

 

优化域名的散列表大小


http {
server_names_hash_bucket_size 128;
}

参数作用:设置存放域名( server names)的最大散列表的存储桶( bucket)的大小。 默认值依赖 CPU 的缓存行。

​server_names_hash_bucket_size​​​ 的值是不能带单位 的。配置主机时必须设置该值,否则无法运行 Nginx,或者无法通过测试 。 该设置与 ​​server_ names_hash_max_size​​​ 共同控制保存服务器名的 hash 表, hash bucket size 总是等于 hash 表的大小, 并且是一路处理器缓存大小的倍数。若 hash bucket size 等于一路处理器缓存的大小,那么在查找键时, 最坏的情况下在内存中查找的次数为 2。第一次是确定存储单元的地址,第二次是在存储单元中查找键值 。 若报 出 hash max size 或 hash bucket size 的提示,则需要增加 ​​server_names_hash_max size​​ 的值。

 

TCP 优化


http {
sendfile on;
tcp_nopush on;
keepalive_timeout 120;
tcp_nodelay on;
}

第一行的 ​​sendfile​​ 配置可以提高 Nginx 静态资源托管效率。sendfile 是一个系统调用,直接在内核空间完成文件发送,不需要先 read 再 write,没有上下文切换开销。

TCP_NOPUSH 是 FreeBSD 的一个 socket 选项,对应 Linux 的 TCP_CORK,Nginx 里统一用 ​​tcp_nopush​​​ 来控制它,并且只有在启用了 ​sendfile​ 之后才生效。启用它之后,数据包会累计到一定大小之后才会发送,减小了额外开销,提高网络效率。

TCP_NODELAY 也是一个 socket 选项,启用后会禁用 Nagle 算法,尽快发送数据,某些情况下可以节约 200ms(Nagle 算法原理是:在发出去的数据还未被确认之前,新生成的小数据先存起来,凑满一个 MSS 或者等到收到确认后再发送)。Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 ​​tcp_nodelay​​。

优化连接参数

http {
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
client_max_body_size 20m;
client_body_buffer_size 10m;
}

client_header_buffer_size:该指令用来设置nginx服务器允许的客户端请求头部缓冲区大小,默认是1K,此指令的复制可以根据系统分页大小来设置,分页可以根据下面指令获得:

[root@www ~]# getconf PAGESIZE
4096

如果你遇到Nginx服务器返回400的错误情况,查找nginx服务器的400错误原因比较困难,因为此错误并不是每次都出现,出现此错误的时候,通常在浏览器和日志里面也看不到任何有关提示信息,根据经验来看,有很大部分原因是客户端请求头部过大造成的。请求头部过大,通常是客户端cookie中写入了较大值引起的。于是适当增加此指令的赋值,允许Nginx服务器接收最大请求头部,可以改善服务器对客户端的支持能力,一般将该值设置为4K.

这部分更多是更具业务场景来决定的。例如​client_max_body_size​用来决定请求体的大小,用来限制上传文件的大小。上面列出的参数可以作为起始参数。

 

配置压缩优化


Gzip 压缩

我们在上线前,代码(JS、CSS 和 HTML)会做压缩,图片也会做压缩(PNGOUT、Pngcrush、JpegOptim、Gifsicle 等)。对于文本文件,在服务端发送响应之前进行 GZip 压缩也很重要,通常压缩后的文本大小会减小到原来的 1/4 - 1/3。

http {
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 3;
gzip_http_version 1.0;
gzip_min_length 1000;
gzip_proxied any;
gzip_vary on;
gzip_types
text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
text/javascript application/javascript application/x-javascript
text/x-json application/json application/x-web-app-manifest+json
text/css text/plain text/x-component
font/opentype application/x-font-ttf application/vnd.ms-fontobject
image/x-icon;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
}

这部分内容比较简单,只有两个地方需要解释下:

​gzip_vary​​ 用来输出 Vary 响应头,用来解决某些缓存服务的一个问题。

​gzip_disable​​ 指令接受一个正则表达式,当请求头中的 UserAgent 字段满足这个正则时,响应不会启用 GZip,这是为了解决在某些浏览器启用 GZip 带来的问题。

默认 Nginx 只会针对 HTTP/1.1 及以上的请求才会启用 GZip,因为部分早期的 HTTP/1.0 客户端在处理 GZip 时有 Bug。现在基本上可以忽略这种情况,于是可以指定 gzip_http_version 1.0 来针对 HTTP/1.0 及以上的请求开启 GZip。

Brotli 压缩

Brotli 是基于LZ77算法的一个现代变体、霍夫曼编码和二阶上下文建模。Google软件工程师在2015年9月发布了包含通用无损数据压缩的Brotli增强版本,特别侧重于HTTP压缩。其中的编码器被部分改写以提高压缩比,编码器和解码器都提高了速度,流式API已被改进,增加更多压缩质量级别。

需要安装​​libbrotli ​​​、​​ngx_brotli ​​​,重新编译 Nginx 时,带上​​--add-module=/path/to/ngx_brotli​​即可,然后配置如下

http {
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
}

Brotli 可与 Gzip 共存在一个配置文件中

 

静态资源优化


静态资源优化,可以减少连接请求数,同时也不需要对这些资源请求打印日志。但副作用是资源更新可能无法及时。

server {
# 图片、视频
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
}
# 字体
location ~ .*\.(eot|ttf|otf|woff|svg)$ {
expires 30d;
access_log off;
}
# js、css
location ~ .*\.(js|css)$ {
expires 7d;
access_log off;
}
}