目标
希望本章讲解,大家可以灵活配置nginx参数,配出最优的nginx服务器。
1,下面为一个nginx配置文件的框架,注释的意思是在代码层面区分,配置文件存储的结构。server是可以同时出现多个的,当出现多个时,通过listen,server_name来区分具体请求的是哪个虚拟主机。
#NGX_MAIN_CONFevents {}http {#NGX_HTTP_MAIN_CONFupstream getUserInfo_proxy {#NGX_HTTP_UPS_CONF} server {#NGX_HTTP_SRV_CONF listen 80; server_name status.360buy.com; location / {#NGX_HTTP_LOC_CONF} } server { listen 80; server_name status.jd.com; }}
2,在main这层级,影响性能的配置主要有下面几个。
user 为了让其他用户可以reload,nginx服务器,我们通常把nginx启动的用户设置成非root用户,这个是为线上配置方便设置的,如果你用的是自动部署,每次发布代码要执行reload,那这个参数会很有用的。
worker_processes 指定nginx的worker数量,通常为总核数减1。减掉的1就是0号cup,因为0号cpu要负责一些系统调度,和软中断操作,如果0号cpu使用率高会影响整体服务器的性能。
worker_cpu_affinity 绑核操作,这个是nginx提高性能的一个重要配置,主要是为了减少nginx进程之间的切换。掩码配置看着很乱,其实只要写总核数-1个0,然后加一个可以自由挪动1即可,1所在的位置就是绑定几号CPU(这是一个比较笨的方法,但是很管用)。像下面的例子就是,一个24核的服务器,让出前6个核(我们线上前5个核是给redis的,在加0号cpu给系统)
pid 这个就是设置nginx启动后pid所得的位置,如果线上是自动化部署nginx服务器,这个就很有用。
worker_rlimit_nofile 更改worker进程的最大打开文件数限制,防止nginx出现"too many open files"错误,这个参数跟系统设置的可打开最大文件句柄有关系。
user admin admin;worker_processes 18;worker_cpu_affinity 000000000000000001000000 000000000000000010000000 000000000000000100000000 000000000000001000000000 000000000000010000000000 000000000000100000000000 000000000001000000000000 000000000010000000000000 000000000100000000000000 000000001000000000000000 000000010000000000000000 000000100000000000000000 000001000000000000000000 000010000000000000000000 000100000000000000000000 001000000000000000000000 010000000000000000000000 100000000000000000000000;pid logs/nginx.pid;worker_rlimit_nofile 102400;
3,在events事件模块中影响性能的重要配置有下面几个
use 选择事件驱动模型,nginx的异步非阻塞全靠事件模型来驱动,这个参数可以说是nginx的核心配置项。目前nginx可选的事件模型有select,poll,kqueue,epoll,rtsig,/dev/poll,eventport。select,在linux,windown上通用,原理是首先创建关注描述符的集合,可关注read,write,exception集合,分别收集事件,然后调用系统函数select(),轮询所有描述符,检查是否有事件发生。缺点:需要轮询所有描述符,效率不高。poll,只在linux系统中使用。跟select不同的是,可以给read ,write ,exception 分别创建描述符集合,分别轮询标识符看是否有事件发生需要处理。这种方式控制更加精细,效率也大幅度提高。epoll,只在linux中使用。跟select,poll不同,把订阅的时间描述符交有内核处理,一旦某个事件发生,内核把发生的事件描述符列表通知给进程。把事件触发交给内核处理进一步提升了效率。
accept_mutex 默认为为on. 将会对多个Nginx进程接受链接进行序列号,防止多个进程对链接进行争抢,只有为on时才可防止惊群现象,和worker负载不均衡的现象。
multi_accept 设置worker process是否可以同时接收多个新到的的网络连接。off:每个worker process一次只能接收一个新到达的网络连接。
worker_connections 每一个worker process同时开启的最大连接数,默认512,不能大于操作系统支持的最大文件句柄数
events { use epoll; accept_mutex on; multi_accept on; accept_mutex_delay 10ms; worker_connections 512000;}
4,nginx在作为反向代理时的重要配置upstream
server 是upstream中的重要配置,实例如下所示。如果回源服务器在本机可以使用 Unix Domain Socket,跳过底层网卡直接使用进程间通信。京东实时价格就是把nginx和redis安装在一台服务,通过lua脚本编写业务逻辑。实现无网络IO的高性能实时价格读取服务。实现本地读取redis数据,只需要开启redis的unixsocket配置即可,具体配置(unixsocket /export/Data/redis_sock/redis_6379.sock unixsocketperm 777)下面看一下,server连接串中的几个关键配置:
weight 权重高的优先用于处理请求
max_fails 请求失败的次数。在一定的时间范围内当对组内某台服务器请求失败次数超过设定值时,认为该服务器无效(down)默认为1,如果设置0则不使用该方法检测服务器是否有效。404不被认为是请求失败。
fail_timeout 有两个作用:1,指定max_fails中请求失败中说的“一定时间范围”,例如下面例子中的配置及1s内3次失败。 2,检查服务器恢复可用的时间间隔,如果一台服务器被认为是无效(down)的,该时间内一致认为是无效的,不在检查服务器的状态。
backup 将组内某台服务器标记为备用服务器。只有当正常服务器处于无效(down)或繁忙(busy),该服务器才被用来处理客户端请求
down 将组内某台服务器标记为永久失效,通常跟ip_hash一起使用。
ip_hash 不能跟weight变量一起使用
keepalive 每一个工作进程允许该服务器组保持的空闲网络连接数的上限值。如果超过该值,工作进程将采用最近最少使用策略关闭网络连接。该值不宜设置的过大,否则会影响服务组与新网络连接的建立
upstream redis_6379{ #Unix Domain Socket 通信方式 server unix:/export/Data/redis_sock/redis_6379.sock weight=1 max_fails=3 fail_timeout=1s; #ip跨网络通信方式 #server 127.0.0.1:6379 weight=1 max_fails=3 fail_timeout=1s; keepalive 512;}
5,nginx扩展模块的几个关键配置
下面的几个配置对我们部署一台前端的nginx服务器还是很重要的,他可以让我们的nginx服务器更加安全可靠。
5.1,ngx_http_limit_req_module简单粗暴的限制前端访问频率和访问量。在发生DDOS攻击时,这几个参数兴许会救你一命。
limit_req_zone 设置ip每秒的访问频率及例子中的160,和20m的桶,也就是会话状态储存的空间
limit_req 开启整个nginx服务器http,或某个server, 或者某个location的防刷配置,如果超过请求阈值就进行拒绝。如果被拒绝,前端默认收到503错误。
limit_req_status 修改被拒绝时前端的错误码,防止跟其他错误混淆。
http { limit_req_zone $binary_remote_addr zone=one:20m rate=160r/s; ... server { ... location /search/ { #下面两个参数也可以作用在server下 limit_req zone=one burst=160 nodelay; limit_req_status 508; }
5.2,当nginx在公司网络中处于lvs下层,或其他代理服务器下层时,可能就需要这个模了 http_realip_module,在公司网络中,常常需要选择性下传,京东就是这样,代理服务器会把外网的ip封装到“J-Forwarded-For”的请求头中进行往下传。这时nginx防刷limit_req,要想生效就需要设置这个模块,否则就防成上层的代理服务器了。那就悲剧了!
下面几个参数在使用的时候,需要在nginx的configure时加上模块 --with-http_realip_module
real_ip_recursive 如果设置on可以获取到真是请求的地址,off只能获取上层服务器的地址。
real_ip_header 设置使用哪个头来替换IP地址。如果使用了J-Forwarded-For,那么该模块将会使用J-Forwarded-For头中的最后一个IP地址来替换前端代理的IP地址
set_real_ip_from 指定信任的地址,也就是上层代理在这些ip网段内,才执行"J-Forwarded-For"替代,这个配置要和real_ip_header配合使用
real_ip_header J-Forwarded-For;real_ip_recursive on;set_real_ip_from 192.168.0.0/16;set_real_ip_from 172.0.0.0/8;
6,nginx在作为代理服务器时,经常需要统计当前服务器的一个请求量,调用量。这个配置就可以满足大家的需求ngx_http_stub_status_module。
下面几个参数在使用的时候,需要在nginx的configure时加上模块 --with-http_stub_status_module
stub_status 值为on是就配置当前location为stub_status模块。
allow 当前location允许访问的ip段
deny 值为all意思是除了allow中的网段,其他网段都禁止访问。
location返回的结果我就不再这里累赘了。大家可以去官网看一下。
location /status {stub_status on;allow 192.168.0.0/16;allow 172.17.0.0/16;allow 10.0.0.0/8;deny all; }
7,下面这个配置很简单,却可以实现一个简单的服务保护。
在http下添加默认server,添加了如下server后,访问非配置过的server_name或listen的请求,均会打到这个默认的server上。如果你的nginx服务器是给固定的域名使用,这个配置就可以防止ip+80端口访问,以及一些非正当请求。
server { listen 80 default_server; access_log off; error_log /dev/null; server_name _ 0.yes.no; root /export/servers/nginx/html; index index.html;}
8,下面来看一些nginx的基本的配置说明
server { listen 80;#绑定的域名 server_name abc.com; #默认文件 index index.shtml index.html index.htm;#网站根目录 root html;#永久分配客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。 client_header_buffer_size 4k;#仅需在处理大header时才会分配更多的空间,从而减少无谓的内存空间浪费 large_client_header_buffers 4 4k;#设置读取客户端body体的缓冲取大小,超过这个大小的body会被截取 client_body_buffer_size 128k;#设置请求的body的最大值,超过返回413错误 client_max_body_size 1m;#隐藏nginx版本号 server_tokens off;#在kernel2.0+ 版本中,系统的网络io优化参数。sendfile() 不但能减少上下文切换次数还能减少拷贝次数。#off 的情况网络io的拷贝过程, 硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈#on 的情况网络io的拷贝过程,硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈 sendfile on;#当使用sendfile函数时,tcp_nopush才起作用,它和指令tcp_nodelay是互斥#on 会设置调用tcp_cork方法,这个也是默认的,获得数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞 tcp_nopush on; tcp_nodelay on;#服务器端保持链接10s,客户端保持链接6s。0表示关闭长连接#keepalive_timeout 10 6; keepalive_timeout 0;#默认该指令设置为off,即不开启gzip功能,只有在该指令为on时,下面的指令才有效 gzip on;#当页面的大小大于该值时,才启用gzip功能。响应页面的大小通过HTTP响应头部中的Content-Length指令获取,但是如果使用了Chunk编码动态压缩,Content-Length或不存在或被忽略,该指令不起作用。设置0统统压缩 gzip_min_length 1k;#设置gzip压缩文件使用缓存空间的大小,gzip_buffers number size; number指定nginx服务器需要向系统申请缓存空间的个数, gzip_buffers 4 16k;#针对指定http以上版本才开启gzip压缩。为了解决老版本乱码问题。 gzip_http_version 1.1;#压缩程度1-9,级别1压缩程度最低,压缩率最高,9压缩程度最高,压缩率最低,最浪费时间。 gzip_comp_level 2;#被设置的类型,将会被压缩。 gzip_types text/plain application/x-javascript application/json text/css text/shtml application/xml;#设置gzip功能是否发送带“Vary:Accept-Encoding”头域的响应头部,头域的主要功能是告诉接收方发送的数据进行了压缩处理。默认off。达到的效果和add_header Vary Accept-Encoding gzip; 一样 gzip_vary on;#gzip_disable "MSIE[1-6]\.";#ie1-6版本不使用gzip压缩 proxy_connect_timeout 1s; #nginx跟后端服务器连接超时时间(代理连接超时) #nginx服务器向后端被代理的服务器(组)发出read请求后,等待响应的超时时间。默认60s proxy_read_timeout 1s; #nginx服务器向后端被代理的服务器(组)发出write请求后,等待响应的超时时间。默认60s proxy_send_timeout 1s; #配置开启关闭Proxy Buffer。默认on。如果off,Nginx服务器只要接受到响应数据就会同步的传给客户端,他本身不会读取完整的响应数据#proxy_buffering on | off;#接受一次被代理服务响应数据的Proxy Buffer总大小 4*32 ,32K这个值一般设置为内存页的大小。 proxy_buffers 4 32k;#配置从被代理服务器获取的第一部分响应数据的大小,该数据中一般包含了HTTP响应头。Nginx服务器通过它来获取响应数据和被代理服务器的一些必要信息。 proxy_buffer_size 4k;#用于限制同时处于BUSY状态的Proxy Buffer的总大小。 proxy_busy_buffers_size 64k;#如果Proxy Buffer被装满后,响应数据仍然没有被Nginx服务器完全接收,响应的数据就会被临时存到磁盘的临时文件中。#该指令用于配置同时写入临文件数据量的总大小。合理设置可以避免磁盘IO负载过重导致系统性能下降问题。 proxy_temp_file_write_size 256k; proxy_set_header Host p.3.cn; #nginx在作为反向代理时把得到的ip传到上次代理服务器中。 proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header J-Forwarded-For $remote_addr;#如果使用upstream指令配置了一组服务器作为被代理服务器,服务器组中各个服务器的访问遵循upstream指令配置的轮询规则,同时可以使用该指令配置在发生那些异常情况时,将请求交有下一个组内服务器处理。#error在建立连接,向被代理的服务器发送请求或者读取响应头时服务器发生链接错误。#timeout,在建立连接,向被代理的服务器发送请求或者读取响应头时服务器发生链接超时。#invalid_header,被代理的服务器返回的响应头为空或者无效。#http_500...,被代理的服务器返回500...#off,无法将请求发送给被代理的服务器 proxy_next_upstream http_500 http_502 http_503 http_504 error timeout invalid_header;#设置nginx服务器提供代理服务的http协议版本。默认1.0。1.1版本支持upsteam服务器组设置中的keepalive指令#proxy_http_version 1.0 | 1.1;...
这些配置主要是在工作中遇到的问题,和经过大量线下压测,总结所得。当然也有网络的收集,如果需要看其他配置项,建议直接查看nginx官方文档(),那里详细介绍了参数使用在哪个级别中,以及配置实例。