Nginx高并发下的优化

Nginx高并发下的优化

写在前面

最近在进行服务器的优化,正好在看nginx相关的知识,所以把一些知识整理一下。参考资料为《Nginx高性能web服务器详解》,建议大家都去读读这本书。 我的机器为四核CPU,16G内存。

内核参数优化

把如下的参数追加到Linux系统的/etc/sysctl.conf文件中,然后使用如下命令使修
改生效:/sbin/sysctl -p
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1

net.core.netdev_max_backlog参数

参数net.core.netdev_max_backlog,表示当每个网络接口接受数据包的速率比内核处理这些包的速率快时,允许发送队列的数据包的最大数目,我们调整为262144.

net.core.somaxconn

该参数用于调节系统同时发起的TCP连接数,一般默认值为128,在客户端高并发的请求的情况下,该默认值较小,可能导致连接超时或者重传问题,我们可以根据实际情况结合并发数来调节此值。

net.ipv4.tcp_max_orphans

该参数用于设定系统中最多允许存在多少TCP套接字不被关联到任何一个用户文件句柄上,如果超过这个数字,没有与用户文件句柄关联到TCP套接字将立即被复位,同时发出警告信息,这个限制只是为了简单防治Dos攻击,一般系统内存充足的情况下,可以增大这个参数。

net.ipv4.tcp_max_syn_backlog

该参数用于记录尚未收到客户端确认信息的连接请求的最大值,对于拥有128内存的系统而言,此参数的默认值为1024,对小内存的系统则是128,一般在系统内存比较充足的情况下,可以增大这个参数的赋值

net.ipv4.tcp_timestamps

该参数用于设置时间戳,这个可以避免序列号的卷绕,在一个1Gb/s的链路上,遇到以前用过的序列号概率很大,当此值赋值为0时,警用对于TCP时间戳的支持,默认情况下,TCP协议会让内核接受这种异常的数据包,针对Nginx服务器来说,建议将其关闭。

net.ipv4.tcp_synack_retries

该参数用于设置内核放弃TCP连接之前向客户端发送SYN+ACK包的数量,为了建立对端的连接服务,服务器和客户端需要进行三次握手,第二次握手期间,内核需要发送SYN并附带一个回应前一个SYN的ACK,这个参数主要影响这个过程,一般赋予值为1,即内核放弃连接之前发送一次SYN+ACK包。

net.ipv4.tcp_syn_retries

该参数的作用与上一个参数类似,设置内核放弃建立连接之前发送SYN包的数量,赋值为1。

nginx优化

nginx主的配置文件如下:

user nginx;
worker_processes 2;
worker_cpu_affinity 0001 0010;
worker_rlimit_nofile 1024;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
use epoll;
multi_accept on;
}

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

log_format main 'remote_user [request" '
'body_bytes_sent "http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 65;

reset_timedout_connection on;
send_timeout 10;
types_hash_max_size 1024;
client_header_buffer_size 4k;
client_max_body_size 8m;

gzip on;
gzip_disable "msie6"
gzip_min_length 1k;
gzip_comp_level 4;
gzip_vary on;
gzip_static on;
gzip_buffers 4 32k;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_http_version 1.1;

include /etc/nginx/conf.d/*.conf;
}

worker_processes (cpu内核)

worker_processes用来设置Nginx服务的进程数。推荐是CPU内核数或者内核数的倍数,推荐使用CPU内核数,因为我的CPU为4核的,所以设置为4。

worker_cpu_affinity (cpu优化)

默认情况下,Nginx的多个进程有可能跑在某一个CPU或CPU的某一核上,导致Nginx进程使用硬件的资源不均,因此绑定Nginx进程到不同的CPU上是为了充分利用硬件的多CPU多核资源的目的。
worker_cpu_affinity用来为每个进程分配CPU的工作内核,参数有多个二进制值表示,每一组代表一个进程,每组中的每一位代表该进程使用CPU的情况,1代表使用,0代表不使用。所以我们使用worker_cpu_affinity 0001 0010 0100 1000;来让进程分别绑定不同的核上。

worker_processes 4;

$nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。

比如4核配置:

worker_cpu_affinity 0001 0010 0100 1000

比如8核配置:

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

为每个进程分配cpu,上例中将8 个进程分配到8 个cpu,当然可以写多个,或者将一个进程分配到多个cpu。

逻辑CPU个数:

cat /proc/cpuinfo | grep "processor" | wc -l


物理CPU个数:

cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l


每个物理CPU中Core的个数:

cat /proc/cpuinfo | grep "cpu cores" | wc -l

worker_rlimit_nofile(最大打开文件数)

进程的最大打开文件数限制。这样nginx就不会有“too many open files”问题了。

该指令是当一个Nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit-n)与nginx进程数相除,但是Nginx分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致

$ worker_rlimit_nofile 1024; #最好与ulimit -n保持一致

当nginx充当反向代理服务器时max_client的计算

$ max_client = worker_processes * worker_connections / 4
max_client表示的是nginx充当反向代理服务器时可同时承载的最大连接数,但是为什么需要处理4呢?这是因为在反向代理时,浏览器会和nginx建立2条连接,nginx也会建立对应的2条连接到后端服务器,因此就有4条连接了,所以需要除以4.

worker_connections(worker最大连接数)

设置一个进程理论允许的最大连接数,理论上越大越好,但不可以超过worker_rlimit_nofile的值。还有个问题,linux系统中有个指令open file resource limit,它设置了进程可以打开的文件句柄数量,可以用下面的指令查看你的linux系统中open file resource limit指令的值,`

echo "2390251" > /proc/sys/fs/file-max; sysctl -p

worker_connections:表示nginx的工作进程(worker process)可以允许建立的外部连接数。指的是单个worker对并发的最大连接数。


在Nginx运行的时候,会启动两种进程,一种是主进程master process;一种是工作进程worker process。如果我在配置文件中将worker_processes设置为4,启动Nginx后,使用进程查看命令观察名字叫做nginx的进程信息,我会看到如下结果:
一个nginx主进程(master process);
四个工作进程(worker process)。
主进程负责监控端口,协调worker进程的工作状态,分配工作任务,worker进程负责进行任务处理。一般这个参数要和操作系统的CPU内核数成倍数。

注意:

worker_connections:这个属性是指单个工作进程可以允许同时建立外部连接的数量。无论这个连接是外部主动建立的,还是内部建立的。一个工作进程(worker process)建立一个连接后,进程将会打开一个文件副本,所以这个数(worker_connections)的大小还和操作系统设定的进程最大可打开的文件副本数有关。

进程的最大连接数受 Linux 系统进程的最大打开文件数限制,只有执行了 "ulimit -HSn 65535" 之后,worker_connections 才能生效
events {

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

worker_connections 65535; #添加的
}

use epoll(epoll模型)

设置事件驱动模型使用epoll。事件驱动模型有select、poll等。

  • select先创建事件的描述符集合,对于一个描述符,可以关注其上面的Read事件、Write事件以及Exception事件,所以要创建三类事件描述符集合,分别用来处理Read事件的描述符、Write事件的描述符、Exception事件的描述符,然后调用底层的select()函数,等待事件发生,轮询所有事件描述符集合的每一个事件描述符,检查是否有事件发生,有的话就处理。select效率低,主要是轮询效率低,而且还要分别轮询三个事件描述符的集合。
  • poll方法与select类似,都是先创建一个关注事件的描述符集合,再去等待这些事件发生,然后再轮询描述符集合,检查有无事件发生,如果有,就去处理。不同点是poll为Read事件、Write事件以及Exception事件只创建一个集合,在每个描述符对应的结构上分别设置Read事件、Write事件以及Exception事件。最后轮询的时候,可以同时检察权这三个事件是否发生。可以说,poll库是select库的优化实现。
  • epoll是Nginx支持的高性能事件驱动库之一。是公认的非常优秀的事件驱动模型。和poll库跟select库有很大的不同,最大区别在于效率。我们知道poll库跟select库都是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候,再去轮询检查这个列表,以判断事件是否发生。这样在描述符多的应用中,效率就显得比较低下了。一种比较好的方式是把列表的管理交由内核负责,一旦某种事件发生,内核就把发生事件的描述符列表通知给进程,这样就避免了轮询整个描述符列表。首先,epoll库通过相关调用同志内核创建一个有N个描述符的事件列表,然后给这些描述符设置所关注的事件,并把它添加到内核的事件列表中去。完成设置以后,epoll库就开始等待内核通知事件发生了,某一事件发生后,内核讲发生事件的描述符列表上报给epoll库,得到事件列表的epoll库,就可以进行事件处理了。epoll库在linux平台是高效的,它支持一个进程打开大数目的事件描述符,上限是系统可以打开文件的最大数目;同时,epoll库的IO效率不随描述符数量的增加而线性下降,因为它只会对内核上报的活跃的描述符进行操作。
    $ use epoll #打开epoll,默认是关闭的

mutex_accept

multi_accept告诉nginx收到一个新连接通知后,尽可能接受链接。当然,得让他开着。

$ multi_accept on;

sendfile(传输文件)

使用开启或关闭是否使用sendfile()传输文件,普通应用应该设为on,下载等IO重负荷的应用应该设为off,因为大文件不适合放到buffer中。

传统文件传输中(read/write方式)在实现上3其实是比较复杂的,需要经过多次上下文切换,当需要对一个文件传输时,传统方式是:

  • 调用read函数,文件数据被copy到内核缓冲区
  • read函数返回,数据从内核缓冲区copy到用户缓冲区
  • write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区
  • 数据从socket缓冲区copy到相关协议引擎
    从上面可以看出来,传统readwrite进行网络文件传输的方式,在过程中经历了四次copy操作。
    硬盘->内核buffer->用户buffer->socket相关缓冲区->协议引擎
    而sendfile系统调用则提供了一种减少多次copy,提高文件传输性能的方法。流程如下:
  • sendfile系统效用,文件数据被copy至内核缓冲区
  • 记录数据文职和长度相关的数据保存到socket相关缓存区
  • 实际数据由DMA模块直接发送到协议引擎
    $ sendfile on; #默认打开

tcp_nopush

sendfile为on时这里也应该设为on,数据包会累积一下再一起传输,可以提高一些传输效率。
$ tcp_nopush on;默认打开

tcp_nodelay

看上去是和tcp_nopush相反的功能,但是两边都为on时nginx也可以平衡这两个功能的使用这个能够提高高频发送小数据报文的实时性。系统存在高频发送小数据报文的时候,打开它。
$ tcp_nodelay on; #小的数据包不等待直接传输。默认为on。

keepalive_timeout

配置连接 keep-alive 超时时间,服务器将在超时之后关闭相应的连接。指定了与客户端的 keep-alive 链接的超时时间。服务器会在这个时间后关闭链接。keep-alive设置过小客户端和服务器会频繁建立连接;设置过大由于连接需要等待keep-alive才会关闭,所以会造成不必要的资源浪费。

$ keepalive_timeout 65; #默认65

reset_timedout_connection

允许server在client停止响应以后关闭连接,释放分配给该连接的内存。当有大并发需求时,建议打开。

$ reset_timedout_connection off; #默认off

send_timeout

设置Nginx服务器响应客户端的超时时间,这个超时时间只针对两个客户端和服务器建立连接后,某次活动之间的时间,如果这个时间后,客户端没有任何活动,Nginx服务器将关闭连接,将其设置为10s,Nginx与客户端建立连接后,某次会话中服务器等待客户端响应超过10s,就会自动关闭。
$ send_timeout 10;

types_hash_max_size

types_hash_max_size影响散列表的冲突率。types_hash_max_size越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。types_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能上升。

$types_hash_max_size 1024; #默认1024

client_header_buffer_size

该指令用于设置Nginx服务器允许的客户端请求头部的缓冲区大小,默认为1KB,此指令的赋值可以根据系统分页大小来设置,分页大小可以用以下命令获取getconf PAGESIZE

$ client_header_buffer_size 4k;

client_max_body_size

客户端上传的body的最大值。超过最大值就会发生413(Request Entity Too Large)错误。默认为1m,最好根据自己的情况改大一点。

$ client_max_body_size 8m;

limit_conn

limit_conn_zone设置用于保存各种key(比如当前连接数)的共享内存的参数.5m就是5兆字节,这个值应该被设置的 足够大以存储(32K5)32byte状态或者(16K5)64byte状态

limit_conn addr为给定的key设置最大连接数.这里key是addr,我们设置的值是100,也就是说我们允许每一个IP地 址最多同时打开有100个连接

binary_remote_addr zone=addr:5m;
$ limit_conn addr 100;

proxy(后端服务器超时时间是否合理)

proxy_connect_timeout :后端服务器连接的超时时间_发起握手等候响应超时时间

proxy_read_timeout:连接成功后等候后端服务器响应时间其实已经进入后端的排队之中等候处理(也可以说是后端 服务器处理请求的时间)

proxy_send_timeout :后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据

proxy_send_timeout #默认60
$ proxy_connect_timeout #默认60

open_file_cache

句法: open_file_cache off;

      open_file_cache max=N [inactive=time]; 

默认: open_file_cache off;

语境: http,server,location

open_file_cache打开缓存的同时也指定了缓存最大数目,以及缓存的时间我指定了20s,所以等到至少20s不访问这个文件,相应缓存的这个文件的更改信息才会被删除。

$ open_file_cache max=100000 inactive=20s;

open_file_cache_valid在open_file_cache指多长时间检查一次缓存的有效信息。也就是说即使我一直访问这个文件,30s后会检查此文件的更改信息是否变化,发现变化就更新

$ open_file_cache_valid 30s;

open_file_cache_min_uses 定义了open_file_cache中指令参数不活动时间期间里最小的文件数,如果超过这个数字,文件更改信息一直是在缓存中打开的

$ open_file_cache_min_uses 2;

open_file_cache_errors指定了当搜索一个文件时是否缓存错误信息,

$ open_file_cache_errors off;

gzip on

启用gzip,对响应数据进行在线实时压缩,减少数据传输量。
$ gzip on

gzip_disable

Nginx服务器在响应这些种类的客户端请求时,不使用Gzip功能缓存应用数据,gzip_disable "msie6"对IE6浏览器的数据不进行GZIP压缩。

$ gzip_disable "msie6";

gzip_min_length

Gzip压缩功能对大数据的压缩效果明显,但是如果压缩很小的数据,可能出现越压缩数据量越大的情况,因此应该根据相应页面的大小,选择性开启或者关闭Gzip功能。建议将值设置为1KB。

警告:如果一个请求小于1K,我们最好不要压缩它,因为压缩这些小的数据会降低处理此请求的所有进程的速度

$ gzip_min_length 1k; #最小1K的文件才启动压缩

gzip_comp_level

设置压缩程度,包括级别1到级别9,级别1表示压缩程度最低,压缩效率最高;级别9表示压缩程度最高,压缩效率最低,最费时间。

$ gzip_comp_level 9; #压缩的级别

gzip_vary

用于设置在使用Gzip功能时是否发送带有“Vary:Accept-Encoding”头域的响应头部,该头域的主要功能是告诉接收方发送的数据经过了压缩处理,开启后端效果是在响应头部Accept-Encoding: gzip,对于本身不支持Gzip的压缩的客户端浏览器是有用的。

$ gzip_vary on; #让前边的缓存服务器识别压缩后的文件

gzip_buffers;

该指令用于设置Gzip压缩文件使用存储空间的大小,

语法: number: 指定Nginx服务器需要向系统申请存储空间的个数,
size: 指定每个缓存空间的大小。 根据配置项,Nginx服务器在对响应输出数据进行Gzip压缩时需向系统申请number*size大小的空间用于存储压缩数据。默认情况下,number*size的值为128,其中size的值为系统内存页一页的大小,用`getconf PAGESIZE`来获取 gzip_buffers 4 32k; #压缩过程都写到buffer里面,压缩完成才发给客户端

gzip_static

开启时,如果客户端浏览器不支持Gzip处理,Nginx服务器将返回解压后的数据,如果客户端浏览器支持Gzip处理,Nginx服务器忽略该指令设置。仍然返回压缩数据。

$ gunzip_static on; #开启

gzip_types

Nginx服务器可以根据MIME类型选择性开启Gzip压缩功能。该指令涌来设置MIME类型。设置需要压缩的数据格式

$ gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

gzip_http_version

gzip_http_version 默认值: gzip_http_version 1.1(就是说对HTTP/1.1协议的请求才会进行gzip压缩)

注:99.99%的浏览器基本上都支持gzip解压了。但是假设我们使用的是默认值1.1,如果我们使用了proxy_pass进行反向代理,那么nginx和后端的upstream server之间是用HTTP/1.0协议通信的,如果我们使用nginx通过反向代理做Cache Server,而且前端的nginx没有开启gzip,同时,我们后端的nginx上没有设置gzip_http_version为1.0,那么Cache的url将不会进行gzip压缩
$ gzip_http_version 1.1 #gzip版本

查考链接
https://www.cnblogs.com/yuanzai12345/p/5951860.html

https://www.jianshu.com/p/4fa08f2a04ed

https://www.cnblogs.com/zhaijunming5/p/6034614.html

你可能感兴趣的:(Nginx高并发下的优化)