nginx api配置详解(生产级别nginx高性能配置)
nginx api配置详解(生产级别nginx高性能配置)Github地址:笔者在github提供了完整的配置文件,同时包含代理基础组件的conf,这些基础组件都是部署在容器里,通过ingress-nginx暴露到外部,然后在通过nginx(openrestry)暴露到公网。(2).Nginx生产级别高性能配置正文(1).前述
原创;千里行走;
受限图片大小限制,有些图片不是很清晰,可以到微信公众号查看;
目录
(1).前述
(2).Nginx生产级别高性能配置
正文
(1).前述
笔者在github提供了完整的配置文件,同时包含代理基础组件的conf,这些基础组件都是部署在容器里,通过ingress-nginx暴露到外部,然后在通过nginx(openrestry)暴露到公网。
Github地址:
https://github.com/hepyu/k8s-app-config/tree/master/yaml/min-cluster-allinone/nginx
如上图:
nginx.conf是主配置文件(生产级别可用的高性能配置),conf.d下是各个基础组件的nginx反响代理配置文件,nginx.conf.desc中是对nginx.conf每个配置的详细说明和应用场景。
下图是代理的K8s容器中的所有基础组件(conf.d目录):
(2).nginx生产级别高性能配置
位于笔者github:
https://github.com/hepyu/k8s-app-config/blob/master/yaml/min-cluster-allinone/nginx/nginx.conf
详细说明位于:
https://github.com/hepyu/k8s-app-config/blob/master/yaml/min-cluster-allinone/nginx/nginx.conf.desc
配置正文部分:
#nginx有很多参数可以配置在http/server/location中,这三者的区别如下,以client_max_body_size举例:
#三者到区别是:
# http{} 中控制着所有nginx收到的请求。
# 而报文大小限制设置在server{}中,则控制该server收到的请求报文大小。
# 同理,如果配置在location中,则报文大小限制,只对匹配了location 路由规则的请求生效。
#可以选择在http{ }中设置:client_max_body_size 20m;
#也可以选择在server{ }中设置:client_max_body_size 20m;
#还可以选择在location{ }中设置:client_max_body_size 20m;
#指定启动nginx使用的用户
user hpy hpy;
#定义了nginx对外提供web服务时的worder进程数。
#最优值取决于许多因素,包括(但不限于)CPU核的数量、存储数据的硬盘数量及负载模式。
#不能确定的时候,将其设置为可用的CPU内核数将是一个好的开始(设置为"auto"将尝试自动检测它)。
worker_processes auto;
#Nginx默认没有开启利用多核CPU 我们可以通过增加worker_cpu_affinity配置参数来充分利用多核CPU。
#CPU是任务处理,计算最关键的资源,CPU核越多,性能就越好。
worker_cpu_affinity auto;
#worker_processes auto和worker_cpu_affinity auto表示启动的worker process进程数量是cpu个数,且均匀绑定到不同的cpu核上。
#这两个参数配置成功的标志是:每个cpu的使用率基本都是一致的。
#生产情况下,我们一般分配专门机器跑nginx,且只跑nginx,从而最大程度上利用nginx自身高效性和现代cpu的多核高效性。
#指定一个nginx进程可以打开的最多文件描述符数目
#文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,依此类推。Unix 操作系统通常给每个进程能打开的文件数量强加一个限制。更甚的是,unix 通常有一个系统级的限制。所以必须把这个参数调大,否则nginx无法跑满效率。
worker_rlimit_nofile 65535;
#nginx的error_log类型如下(从左到右:debug最详细 crit最少):
#[ debug | info | notice | warn | error | crit ]
#生产环境我们只打error日志;access日志一般是关闭的,否则中断太多,严重影响nginx性能。
error_log /data/hpy/logs/nginx/error.log notice;
#pid位置
pid /app/3rd/nginx/openresty/nginx/conf/nginx.pid;
#events模块中包含nginx中所有处理连接的设置
events{
#使用epoll的I/O 模型,必开项,极其有利于性能。
use epoll;
#worker_connections配置表示每个工作进程的并发连接数,默认设置为1024。
#工作进程的最大连接数量 理论上每台nginx服务器的最大连接数为worker_processes*worker_connections worker_processes为我们在main中开启的进程数。
worker_connections 65535;
}
http {
#HTTP request里面有一个头叫 Accept,列出浏览器可以接受的mime type,HTTP response 的Content-Type 的值 在Accept 里面。
#这个mime.types指定了nginx可以接受的Content-Type;mime.types文件默认位于nginx.conf的同级目录。
include mime.types;
#默认文件类型
#意思是如果一个文件的mime类型不存在就会使用默认的类型。 通常是这个导致了文件的下载。
#将default_type application/octet-stream; 修改为default_type text/html; 这样就默认表示一个文件是 html文件, 就可以在浏览器中查看。
#上面的方面可以解决文件不在浏览器中预览的情况,但是如果有文件的扩展名对应mime信息找不到,也会进行预览, 不管文件是不是文本文件,都是当成是文本文件。
default_type application/octet-stream;
#log_format指令用来设置日志的记录格式,它的语法如下:log_format name format {format ...} 其中name表示定义的格式名称,format表示定义的格式样式。
#"version": "2":
# 自定义,表示当前nginx.conf是第几个版本。方便CMDB管理。
#"time": "$time_iso8601":
# 使用到$time_iso8601 内嵌变量来获取时间。$time_iso8601格式如下:2015-08-07T18:12:02 02:00。
#"remote_addr": "$remote_addr":
# 1.remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的;
# 当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP;
# 如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP;
# 2.但是实际场景中,我们即使有代理,也需要将$remote_addr设置为真实的用户IP,以便记录在日志当中,当然nginx是有这个功能,但是需要编译的时候添加--with-http_realip_module 这个模块,默认是没有安装的。
#"status": "$status":
# 记录请求状态。
#"bytes_sent": "$bytes_sent":
# 发送给客户端的总字节数。
#"host": "$host":
# $host 是nginx的官方变量,可以从官方查询。
# 举例:
# curl --silent -H "Host: www.xxxx.com" "hostname/xxxx/xxxx.htm"
# 这种方式与windows中更改hosts文件,指定域名对应用的具体host的ip是一样的,
# curl http://ww.xxxx.com/xxxx/xxxx.htm -xhostname:80
#"request_method": "$request_method":
# 请求方式:POST GET PUT等。
#"request_uri": "$request_uri":
# 这个变量等于从客户端发送来的原生请求URI,包括参数。它不可以进行修改。
# Example: "/foo/bar.php?arg=baz"
#"uri": "$uri":
# 不带请求参数的当前URI,$uri不包含主机名,如"/foo/bar.html"。
#"request_time": "$request_time":
# 指的就是从接受用户请求的第一个字节到发送完响应数据的时间,即$request_time包括接收客户端请求数据的时间、后端程序响应的时间、发送响应数据给客户端的时间。
#"response_time": "$upstream_response_time":
# 是指从Nginx向后端建立连接开始到接受完数据然后关闭连接为止的时间。
# 从上面的描述可以看出,$request_time肯定比$upstream_response_time值大;尤其是在客户端采用POST方式提交较大的数据,响应体比较大的时候。在客户端网络条件差的时候,$request_time还会被放大。
#"http_referer": "$http_referer":
# 用来记录从那个页面链接访问过来的;可以使用这个参数做防盗链。
#"body_bytes_sent": "$body_bytes_sent":
# 发送给客户端的字节数,不包括响应头的大小。
#"bytes_sent": "$bytes_sent":
# 发送给客户端的总字节数。
#"http_user_agent": "$http_user_agent":
# 记录客户端浏览器相关信息;可以使用这个参数做防盗链。
#"http_x_forwarded_for": "$http_x_forwarded_for":
# REMOTE_ADDR代表着客户端的IP,但是这个客户端是相对服务器而言的,也就是实际上与服务器相连的机器的IP(建立tcp连接的那个),这个值是不可伪造的,如果没有代理的话,这个值就是用户实际的IP值,有代理的话,用户的请求会经过代理再到服务器,这个时候REMOTE_ADDR会被设置为代理机器的IP值。
# 正如前面所说,有了代理就获取不了用户的真实IP,由此X-Forwarded-For应运而生,它是一个非正式协议,在请求转发到代理的时候代理会添加一个X-Forwarded-For头,将连接它的客户端IP(也就是你的上网机器IP)加到这个头信息里,这样末端的服务器就能获取真正上网的人的IP了。
# 假设用户的请求顺序如下:
# 网民电脑ip->代理服务器1–>代理服务器2–>目标服务器
# REMOTE_ADDR:代理服务器2的IP值
# X-Forwarded-For就是:网民电脑IP,代理1的IP,代理2的IP
# 在这里只有REMOTE_ADDR是可信的,其他从客户端获取的数据都是不可信的,都是可伪造的。下面简单示例下一个篡改X-Forwarded-For的情况:
#"coohua_id": "$http_coohua_id":
#"ukey": "$http_u_key":
#"vkey": "$http_v_key":
#"cookie": "$http_cookie":
# 获取全部cookie信息。
log_format access
'{"version": "2" '
'"time": "$time_iso8601" '
'"remote_addr": "$remote_addr" '
'"status": "$status" '
'"bytes_sent": "$bytes_sent" '
'"host": "$host" '
'"request_method": "$request_method" '
'"request_uri": "$request_uri" '
'"request_time": "$request_time" '
'"response_time": "$upstream_response_time" '
'"http_referer": "$http_referer" '
'"body_bytes_sent": "$body_bytes_sent" '
'"http_user_agent": "$http_user_agent" '
'"http_x_forwarded_for": "$http_x_forwarded_for" '
'"coohua_id": "$http_coohua_id" '
'"ukey": "$http_u_key" '
'"vkey": "$http_v_key" '
'"cookie": "$http_cookie"}';
#用来指定日志文件的存放路径。
access_log /data/coohua/logs/nginx/access.log access;
#这个参数指定了是否记录客户端的请求出现404错误的日志。
log_not_found off;
#隐藏版本号
#off:表示赢藏nginx版本号。
server_tokens off;
#开启0拷贝
#零拷贝主要的任务就是避免CPU将数据从一块存储拷贝到另外一块存储,主要就是利用各种零拷贝技术,避免让CPU做大量的数据拷贝任务,减少不必要的拷贝;
#或者让别的组件来做这一类简单的数据传输任务,让CPU解脱出来专注于别的任务。这样就可以让系统资源的利用更加有效。
#当需要对一个文件进行传输的时候,其具体流程细节如下:
#(1).sendfile off(关闭0拷贝)下的流程:
# 1、调用read函数,文件数据被copy到内核缓冲区
# 2、read函数返回,文件数据从内核缓冲区copy到用户缓冲区
# 3、write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。
# 4、数据从socket缓冲区copy到相关协议引擎。
# 以上细节是传统read/write方式进行网络文件传输的方式,我们可以看到,在这个过程当中,文件数据实际上是经过了四次copy操作:
# 硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎
#(2).sendfile on(开启0拷贝)下的流程:
# 1、sendfile系统调用,文件数据被copy至内核缓冲区
# 2、再从内核缓冲区copy至内核中socket相关的缓冲区
# 3、最后再socket相关的缓冲区copy到协议引擎
# 这个过程数据经历的拷贝操作如下:
# 硬盘—>内核缓冲区—>协议引擎
sendfile on;
#tcp_nopush是一个 socket 选项,并且只有在启用了 sendfile 之后才生效(可以理解,只有sendfile开启才能确保tcp_nopush的效率);
#启用它之后,数据包会累计到一定大小之后才会发送,减小了额外开销,提高网络效率。
tcp_nopush on;
#tcp_nodelay也是一个 socket 选项,启用后会禁用 Nagle 算法,尽快发送数据,某些情况下可以节约 200ms;
#Nagle 算法原理是:在发出去的数据还未被确认之前,新生成的小数据先存起来,凑满一个 MSS 或者等到收到确认后再发送;
#Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 tcp_nodelay。
tcp_nodelay on;
#关于tcp_nopush与tcp_nodelay的混合使用:
#可以看到 TCP_NOPUSH 是要等数据包累积到一定大小才发送,TCP_NODELAY 是要尽快发送,二者相互矛盾。实际上,它们确实可以一起用,最终的效果是先填满包,再尽快发送。
#关于这部分内容的更多介绍可以看这篇文章:
# NGINX OPTIMIZATION: UNDERSTANDING SENDFILE TCP_NODELAY AND TCP_NOPUSH。
# url link:https://thoughts.t37.net/nginx-optimization-understanding-sendfile-tcp-nodelay-and-tcp-nopush-c55cdd276765
#指定客户端与服务端建立连接后发送 request body 的超时时间;
#如果客户端在指定时间内没有发送任何内容,Nginx 返回 HTTP 408(Request Timed Out);
#对于弱网用户,尤其是移动用户来说,这个配置是能大幅提供nginx的性能的,防止nginx资源浪费。
# 配置段: http server location
client_body_timeout 10;
#HTTP 是一种无状态协议,客户端向服务器发送一个 TCP 请求,服务端响应完毕后断开连接。
#如果客户端向服务器发送多个请求,每个请求都要建立各自独立的连接以传输数据。
#HTTP 有一个 KeepAlive 模式,它告诉 webserver 在处理完一个请求后保持这个 TCP 连接的打开状态。
#若接收到来自客户端的其它请求,服务端会利用这个未被关闭的连接,而不需要再建立一个连接。
#KeepAlive 在一段时间内保持打开状态,它们会在这段时间内占用资源。占用过多就会影响性能。
#Nginx 使用 keepalive_timeout 来指定 KeepAlive 的超时时间(timeout)。指定每个 TCP 连接最多可以保持多长时间。
#Nginx 的默认值是 75 秒,有些浏览器最多只保持 60 秒,所以可以设定为 60 秒。若将它设置为 0,就禁止了 keepalive 连接。
#通常keepalive_timeout应该比client_body_timeout大。
# 配置段: http server location
keepalive_timeout 60;
#keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。
#默认是100。
#这个参数的真实含义:
# 是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。
# 如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。
#大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000 50000甚至更高) 的场景,默认的100就显得太低。
#简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求。
# 意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。
# 因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。
# 因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。
#对于黏度/交互度很高的用户场景,这个值是能够大幅提供nginx的服务能力的。
keepalive_requests 1000;
#默认值是4K,同pagesize大小,request请求头超过大小nginx会返回400。
#客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为系统分页大小。
#查看系统分页可以使用 getconf PAGESIZE命令
#现在我们很多时候都会往Header里放一堆东西,所以这个值需要根据实际情况调整。
client_header_buffer_size 32k;
#关于client_header_buffer_size和large_client_header_buffers
# 先根据client_header_buffer_size配置的值分配一个buffer,
# 如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,
# 如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。
#large_client_header_buffers设置客户端请求的Header头缓冲区大小,默认为4K。
# 客户端请求行不能超过设置的第一个数,请求的Header头信息不能大于设置的第二个数,否则会报"Request URI too large"(414)或"Bad request"(400)错误。
# 如果客户端的Cookie信息较大,则需增加缓冲区大小
large_client_header_buffers 4 64k;
#这个directive让Nginx将所有的request body存储在一个缓冲当中,它的默认值是off。
#启用它可以优化读取$request_body变量时的I/O性能。可以在http server 和 location模块中定义。
client_body_in_single_buffer on;
#这个directive设定了request body的缓冲大小。
# 如果body超过了缓冲的大小,那么整个body或者部分body将被写入一个临时文件。
# 如果Nginx被设置成使用文件缓冲而不使用内存缓冲,那么这个dirctive就无效。
# client_body_buffer_size在32位系统上默认是8k,在64位系统上默认是16k。
#可以在http server 和 location模块中指定。
client_body_buffer_size 128k;
#相关场景&问题:
# 服务器有时上出现很多499的错误,出现499错误的原因是客户端关闭了连接;
# 服务端在执行时中途关闭浏览器退出之后php/java等后端是否还会继续执行;
#proxy_ignore_client_abort是否开启proxy忽略客户端中断。
# 即如果此项设置为on开启,则服务器会忽略客户端中断,一直等着代理服务执行返回。并且如果执行没有发生错误,记录的日志是200日志。如果超时则会记录504。
# 如果设置为off,则客户端中断后服务器端nginx立即记录499日志,但要注意,此时代理端的PHP/Java程序会依然继续执行。
#nginx的proxy_ignore_client_abort默认是关闭的,即请求过程中如果客户端端主动关闭请求或者客户端网络断掉,那么Nginx会记录499。所以如果不想看到499报错,可以修改配置:proxy_ignore_client_abort on ;
#也就是说,499错误并不是一个问题,如果出现了大量的499的话,需要考虑为什么发生了这么多的客户端中断的问题。
proxy_ignore_client_abort on;
#HTTP头是可以包含英文字母([A-Za-z])、数字([0-9])、连接号(-)hyphens 也可义是下划线(_)。在使用nginx的时候应该避免使用包含下划线的HTTP头。主要的原因有以下2点。
# 1.默认的情况下nginx引用header变量时不能使用带下划线的变量。要解决这样的问题只能单独配置underscores_in_headers on。
# 2.默认的情况下会忽略掉带下划线的变量。要解决这个需要配置ignore_invalid_headers off。
underscores_in_headers on;
ignore_invalid_headers off;
#客户端向服务端发送一个完整的 request header 的超时时间;
#如果客户端在指定时间内没有发送一个完整的 request header,Nginx 返回 HTTP 408(Request Timed Out);
#对于弱网用户,尤其是移动用户来说,这个配置是能大幅提供nginx的性能的,防止nginx资源浪费。
# 配置段: http server location
client_header_timeout 9;
#这条directive指定了向客户端传输数据的超时时间。默认值为60秒,可以在http server 和 location模块中定义。
send_timeout 60;
#三者到区别是:http{} 中控制着所有nginx收到的请求。
# 而报文大小限制设置在server{}中,则控制该server收到的请求报文大小,同理,如果配置在location中,则报文大小限制,只对匹配了location 路由规则的请求生效。
#可以选择在http{ }中设置:client_max_body_size 20m;
#也可以选择在server{ }中设置:client_max_body_size 20m;
#还可以选择在location{ }中设置:client_max_body_size 20m;
#我们使用web上传文件时用nginx做代理必须配置此项,否则文件太大会发生中断。
client_max_body_size 50m;
#网站加载的速度取决于浏览器必须下载的所有文件的大小。减少要传输的文件的大小可以使网站不仅加载更快,而且对于那些宽带是按量计费的人来说也更友好。
#gzip是一种流行的数据压缩程序。您可以使用gzip压缩Nginx实时文件。这些文件在检索时由支持它的浏览器解压缩,好处是web服务器和浏览器之间传输的数据量更小,速度更快。
#gzip不一定适用于所有文件的压缩。
# 例如,文本文件压缩得非常好,通常会缩小两倍以上。
# 另一方面,诸如JPEG或PNG文件之类的图像已经按其性质进行压缩,使用gzip压缩很难有好的压缩效果或者甚至没有效果。
# 压缩文件会占用服务器资源,因此最好只压缩那些压缩效果好的文件。
# mod_gzip configurations
#开启gzip,默认值gzip off(关闭)
gzip on;
#它的默认值是1.1,就是说对HTTP/1.1协议的请求才会进行gzip压缩。
gzip_http_version 1.0;
#gzip的压缩比,1-9个数量级,数据越大,压缩的程度越高,压缩后占用空间越小,但是效率最低,更加消耗CPU,一般为6即可。
gzip_comp_level 6;
#设置一个将要被压缩的响应的最小长度值(即长度小于这个值的响应将不会被压缩)。
#设置这项的主要原因是在数据过小的情况下,压缩效果不明显,不如不进行压缩,建议设置成512,只对大于512的响应数据进行压缩(页面字节数从header头中的Content-Length中进行获取)
gzip_min_length 1k;
#该指令在nginx使用反向代理的时候起作用,是否压缩取决于请求头中的"Via"字段,指令中可以同时指定多个不同的参数。根据请求和响应来决定启用或禁用对代理请求的响应的压缩
# (1)off:禁用对所有代理请求的压缩
# (2) expired:当响应头中包含过期时间时,启用压缩
# (3) no-cache:当响应头的Cache-Control字段为no-cache时,启用压缩
# (4) no-store:当响应头的Cache-Control字段为no-store时,启用压缩
# (5) private:当响应头的Cache-Control字段为no-store时,启用压缩
# --cache_control用于设置缓存机制
# (6)no_last_modified:当响应头不包含响应最后修改时间字段时,启用压缩。
# (7)no_etag:当想用头中不包含被请求变量的实体值时,启用压缩
# (8)auth:当响应头包含用于授权http证书的Authorization字段时,启用压缩
# (9)any:岁所有代理请求开启压缩。
#默认值 gzip_proxied off;
gzip_proxied any;
#该指令用于只用gzip功能时,是否发送Vary: Accept-Encoding响应头字段,通知接收方响应使用了gzip压缩
gzip_vary on;
#不启用压缩的条件,IE6对Gzip不友好,所以不压缩
gzip_disable msie6;
#设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流
# 例如 4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存。 4 8k 代表以8k为单位,按照原始数据大小以8k为单位的4倍申请内存。
# 如果没有设置,默认值是申请跟原始数据相同大小的内存空间去存储gzip压缩结果。
gzip_buffers 4 64k;
#需要压缩的文件mime类型
gzip_types text/xml text/plain text/css application/javascript application/x-javascript application/xml application/json application/rss xml;
#即允许重新定义或添加字段传递给代理服务器的请求头。该值可以包含文本、变量和它们的组合。在没有定义proxy_set_header时会继承之前定义的值。默认情况下,只有两个字段被重定义:
# proxy_set_header Host $proxy_host;
# proxy_set_header Connection close;
# mod_http_proxy
#举例说明$host $proxy_host的使用和区别:
#location /front {
# proxy_pass http://web;
# proxy_set_header Host $proxy_host;
#}
#当匹配到/front时,使用web处理,到upstream就匹配到abc.com,这里直接转换成IP进行转发。
#1.假如abc.com是在另一台nginx下配置的,ip为10.10.10.10,则$proxy_host则对应为10.10.10.10。
# 此时相当于设置了Host为10.10.10.10。如果想让Host是abc.com,则进行如下设置:
# proxy_set_header Host abc.com;
#2.如果不想改变请求头"Host"的值,可以这样来设置:
# proxy_set_header Host $http_host;
#3.但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。
# 这种情况下,更好的方式是使用$host变量——它的值在请求包含"Host"请求头时为"Host"字段的值,在请求未携带"Host"请求头时为虚拟主机的主域名:
# proxy_set_header Host $host;
#4.此外,服务器名可以和后端服务器的端口一起传送:
# proxy_set_header Host $host:$proxy_port;
proxy_set_header Host $host;
#设置真实客户端IP
proxy_set_header X-Real-IP $remote_addr;
#1、X-Forwarded-For的定义:
# X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。
# 标准格式如下:
# X-Forwarded-For: client1 proxy1 proxy2
# 从标准格式可以看出,X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。
#2、依照WEB架构图进行分析
# a.在有CDN的情况下,当用户请求经过CDN后到达Nginx负载均衡服务器时,其X-Forwarded-For头信息应该为 客户端IP CDN的IP 但实际情况并非如此,一般情况下CDN服务商为了自身安全考虑会将这个信息做些改动,只保留客户端IP。
# 我们可以通过php程序获得X-Forwarded-For信息或者通过Nginx的add header方法来设置返回头来查看。
# b.下面来分析请求头到达Nginx负载均衡服务器的情况;在默认情况下,Nginx并不会对X-Forwarded-For头做任何的处理,除非用户使用proxy_set_header 参数设置:
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# $proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr用逗号分开,
# 如果没有"X-Forwarded-For" 请求头,则$proxy_add_x_forwarded_for等于$remote_addr。$remote_addr变量的值是客户端的IP。
# c.当Nginx设置X-Forwarded-For于$proxy_add_x_forwarded_for后会有两种情况发生:
# c1.如果从CDN过来的请求没有设置X-Forwarded-For头(通常这种事情不会发生),而到了我们这里Nginx设置将其设置为$proxy_add_x_forwarded_for的话,X-Forwarded-For的信息应该为CDN的IP,因为相对于Nginx负载均衡来说客户端即为CDN,这样的话,后端的web程序时死活也获得不了真实用户的IP的。
# c2.CDN设置了X-Forwarded-For,我们这里又设置了一次,且值为$proxy_add_x_forwarded_for的话,那么X-Forwarded-For的内容变成 "客户端IP Nginx负载均衡服务器IP"如果是这种情况的话,那后端的程序通过X-Forwarded-For获得客户端IP,则取逗号分隔的第一项即可。
# 如上两点所说,如果我们知道了CDN设置了X-Forwarded-For信息,且只有客户端真实的IP的话,那么我们的Nginx负载均衡服务器可以不必理会该头,让它默认即可。
#其实Nginx中还有一个$http_x_forwarded_for变量,这个变量中保存的内容就是请求中的X-Forwarded-For信息。
#如果后端获得X-Forwarded-For信息的程序兼容性不好的话(没有考虑到X-Forwarded-For含有多个IP的情况),最好就不要将X-Forwarded-For设置为 $proxy_add_x_forwarded_for。
# 应该设置为$http_x_forwarded_for 或者干脆不设置!
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#http协议,HTTP协议中对长连接的支持是从1.1版本之后才有的,因此最好通过proxy_http_version指令设置为"1.1";
#必设项,否则很影响nginx性能。
proxy_http_version 1.1;
#表示nginx每次访问完后端server后,如何处理与后端server的这次请求连接,默认配置是close,即每次访问完后端服务后都关闭此次连接,显然这回给后端server带来大量的TIME_WAIT连接,降低后端server性能。
proxy_set_header Connection "";
#综上,我们总结一下出现TIME_WAIT的情况:
#出现大量TIME_WAIT的情况主要有两种:
# 1)导致 nginx端出现大量TIME_WAIT的情况有两种:
# keepalive_requests设置比较小,高并发下超过此值后nginx会强制关闭和客户端保持的keepalive长连接;(主动关闭连接后导致nginx出现TIME_WAIT)
# keepalive设置的比较小(空闲数太小),导致高并发下nginx会频繁出现连接数震荡(超过该值会关闭连接),不停的关闭、开启和后端server保持的keepalive长连接;
# 2)导致后端server端出现大量TIME_WAIT的情况:
# nginx没有打开和后端的长连接,即:没有设置proxy_http_version 1.1;和proxy_set_header Connection "";从而导致后端server每次关闭连接,高并发下就会出现server端出现大量TIME_WAIT
#在使用Nginx做反向代理功能时,有时会出现重定向的url不是我们想要的url,这时候就可以使用proxy_redirect进行url重定向设置了。
#proxy_redirect功能比较强大 其作用是对发送给客户端的URL进行修改。
#默认:proxy_redirect default;
#配置块(使用的字段):http、server、location
#我们是关闭此项的。
proxy_redirect off;
#语法:proxy_buffers 数量 大小
#默认值:proxy_buffers 8 4k/8k
#上下文:http server location
#该指令设置缓冲区的大小和数量 从被代理的后端服务器取得的响应内容 会放置到这里. 默认情况下 一个缓冲区的大小等于内存页面大小 可能是4K也可能是8K 这取决于平台。
proxy_buffers 64 8k;
#proxy_connect_timeout 是和后端建立连接的超时时间 单位秒,默认值60秒。
proxy_connect_timeout 60;
#缓存临时目录。
#后端的响应并不直接返回客户端,而是先写到一个临时文件中,然后被rename一下当做缓存放在 proxy_cache_path 。
#0.8.9版本以后允许temp和cache两个目录在不同文件系统上(分区),然而为了减少性能损失还是建议把它们设成一个文件系统上
proxy_temp_path /app/3rd/nginx/default/proxy_temp;
#设置缓存目录,目录里的文件名是 cache_key 的MD5值。
# levels=1:2 keys_zone=cache_one:512m:
# 表示采用2级目录结构,Web缓存区名称为cache_one,内存缓存空间大小为512MB,这个缓冲zone可以被多次使用。
# inactive=1d max_size=2g:
# 表示1天没有被访问的内容自动清除,硬盘最大缓存空间为2GB,超过这个大学将清除最近最少使用的数据。
proxy_cache_path /app/3rd/nginx/proxy_cache levels=1:2 keys_zone=cache_one:512m inactive=1d max_size=2g;
# fight DDoS attack tune the numbers below according your application!!!
#默认值: none,不开启
#配置段: http
#设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)。如
# limit_req_zone $binary_remote_addr zone=req:20m rate=1r/s;
# 区域名称为one,大小为20m,平均处理的请求频率不能超过每秒一次。
# 说明:
# 键值是客户端IP。
# 使用$binary_remote_addr变量, 可以将每条状态记录的大小减少到64个字节,这样1M的内存可以保存大约1万6千个64字节的记录。
# 如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
# 速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 "30r/m"。
#limit_req_zone $binary_remote_addr zone=req:20m rate=3r/s;
#语法: limit_req zone=name [burst=number] [nodelay];
#默认值: —
#配置段: http server location
# 设置对应的共享内存限制域和允许被处理的最大请求数阈值。
# 如果请求的频率超过了限制域配置的值,请求处理会被延迟,所以所有的请求都是以定义的频率被处理的。
# 超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值,这时,这个请求会被终止,并返回503 (Service Temporarily Unavailable) 错误。这个阈值的默认值为0。如:
# limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;
# server {
# location /www.ttlsa.com/ {
# limit_req zone=ttlsa_com burst=5;
# }
# 限制平均每秒不超过一个请求,同时允许超过频率限制的请求数不多于5个。
# 如果不希望超过的请求被延迟,可以用nodelay参数 如:
# limit_req zone=ttlsa_com burst=5 nodelay;
#注意:
# 这些都是临时处理手段,不能作为常态,因为一旦超出说明现在负载均衡不够用,应该想办法解决,比如查看是不是有人刷/增加机器/负载均衡调优等。
# 只要在下载场景例外。
#limit_req zone=req burst=60;
#要限制用户的连接数可以通过Limit zone模块来达到目的,即限制同一用户IP地址的并发连接数。
# 该模块提供了两个命令limit_zone和limit_conn,其中limit_zone只能用在http区段,而limit_conn可以用在http server location区段。
#该指令用于定义一个zone,该zome将会被用于存储会话状态。
#能够存储的会话数量是由分被交付的变量和memory_max_size的大小决定的。
#例如:
# limit_zone one $binary_remote_addr 10m;
# 客户端的IP地址被用作会话,注意,这里使用的是$binary_remote_addr而不是$remote_addr;
# 这是因为,$remote_addr的长度为7到15个字节,它的会话信息的长度为 32 或 64 bytes;$binary_remote_addr 的长度为 4 字节,会话信息的长度为 32 字节。
# 当设置1M的一个zone时,那么如果是用$binary_remote_addr方式,该zone将会存放32000个会话。
#limit_zone conn $binary_remote_addr 20m;
#该指令用于为一个会话设定最大的并发连接数。如果并发请求数超过这个限制,那么将会出现"Service unavailable" (503)。
#例如:
limit_zone one $binary_remote_addr 10m;
server {
location /download/ {
limit_conn one 1;
}
#这个设置将会使得来自用同一个IP的并发连接不能超过1个连接。
#limit_conn conn 5;
#设置每一个连接的下载速度。
#limit_rate 50k;
#从下载到你指定的文件大小之后开始限速。
#limit_rate_after 1m;
#如果你定义了大量的服务器名字,或者是定义了少见的长的服务器名字,那么你需要在http级别(或者叫区段)调整指令"server_names_hash_max_size"和"server_names_hash_bucket_size"的值。
#指令"server_names_hash_bucket_size"默认值可以是32、64或者是其他值,这依赖于CPU缓存行(ache line)的大小。
# 如果默认值为32,当你定义"too.long.server.name.nginx.org"作为服务器的名字,那么Nginx将会在启动时失败,并且显示如下错误信息:
# 1. could not build the server_names_hash
# 2. you should increase server_names_hash_bucket_size: 32
# 在以上情况时,应该设置该指令的值为以前值的两倍:
# 1. http {
# 2. server_names_hash_bucket_size 64;
# 3. …
#如果你指定了大量的服务器名字,那么将会遇到另一个错误信息:
# 1. could not build the server_names_hash
# 2. you should increase either server_names_hash_max_size: 512
# 3. or server_names_hash_bucket_size: 32
#
#应该首先尝试设置"server_names_hash_max_size"的值接近于服务器名字的数量。
# 如果修改这个指令的值仍然没有起到作用,或者是当Nginx的启动太慢时,才去尝试增加指令"server_names_hash_bucket_size"的值。
# 如果服务器仅监听在一个端口,那么Nginx根本就不会检测服务器的名字(也不会为该端口建立哈希表)。
# 然而,却有一个例外,如果指令"server_name"的值是一个捕获的正则表达式,那么Nginx不得不执行一个表达式来获取捕获。
#简单理解:
# server_names_hash_max_size表示nginx可以捕获的服务器名字的最大数量。
# server_names_hash_bucket_size表示nginx中每个服务器名字的最大长度。
server_names_hash_max_size 1024;
server_names_hash_bucket_size 128;
include conf.d/*.conf;
}