前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx-1:生产级别nginx高性能配置

nginx-1:生产级别nginx高性能配置

作者头像
千里行走
发布2019-07-03 17:53:17
2.6K0
发布2019-07-03 17:53:17
举报
文章被收录于专栏:千里行走千里行走

目录

(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使用的用户

userhpyhpy;

#定义了nginx对外提供web服务时的worder进程数。

#最优值取决于许多因素,包括(但不限于)CPU核的数量、存储数据的硬盘数量及负载模式。

#不能确定的时候,将其设置为可用的CPU内核数将是一个好的开始(设置为“auto”将尝试自动检测它)。

worker_processesauto;

#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_connectionsworker_processes为我们在main中开启的进程数。

worker_connections 65535;

}

http {

#HTTPrequest里面有一个头叫 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_typetext/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是一样的,

# curlhttp://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_tokensoff;

#开启0拷贝

#零拷贝主要的任务就是避免CPU将数据从一块存储拷贝到另外一块存储,主要就是利用各种零拷贝技术,避免让CPU做大量的数据拷贝任务,减少不必要的拷贝;

#或者让别的组件来做这一类简单的数据传输任务,让CPU解脱出来专注于别的任务。这样就可以让系统资源的利用更加有效。

#当需要对一个文件进行传输的时候,其具体流程细节如下:

#(1).sendfileoff(关闭0拷贝)下的流程:

# 1、调用read函数,文件数据被copy到内核缓冲区

# 2、read函数返回,文件数据从内核缓冲区copy到用户缓冲区

# 3、write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。

# 4、数据从socket缓冲区copy到相关协议引擎。

# 以上细节是传统read/write方式进行网络文件传输的方式,我们可以看到,在这个过程当中,文件数据实际上是经过了四次copy操作:

# 硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎

#(2).sendfileon(开启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(RequestTimed 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_timeout60;

#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连接(即使此时keepalive已经在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 URItoo large"(414)或“Bad request”(400)错误。

# 如果客户端的Cookie信息较大,则需增加缓冲区大小

large_client_header_buffers 4 64k;

#这个directive让Nginx将所有的requestbody存储在一个缓冲当中,它的默认值是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_headerson。

# 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/xmltext/plain text/css application/javascript application/x-javascriptapplication/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_headerConnection “”;从而导致后端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_cachelevels=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_addrzone=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_addrzone=ttlsa_com:10m rate=1r/s;

# server {

# location /www.ttlsa.com/ {

# limit_req zone=ttlsa_comburst=5;

# }

# 限制平均每秒不超过一个请求,同时允许超过频率限制的请求数不多于5个。

# 如果不希望超过的请求被延迟,可以用nodelay参数,如:

# limit_req zone=ttlsa_com burst=5nodelay;

#注意:

# 这些都是临时处理手段,不能作为常态,因为一旦超出说明现在负载均衡不够用,应该想办法解决,比如查看是不是有人刷/增加机器/负载均衡调优等。

# 只要在下载场景例外。

#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_after1m;

#如果你定义了大量的服务器名字,或者是定义了少见的长的服务器名字,那么你需要在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;

includeconf.d/*.conf;

}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 千里行走 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
内容分发网络 CDN
内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档