nginx系列(三)FastCGI与反向代理
一、FastCGI
1.1 FastCGI的介绍
这块介绍部分主要参考:南非蚂蚁的博客:http://ixdba.blog.51cto.com/2895551/806622 还有nginx实战.
什么是FastCGI?
FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能。CGI解释器的反复加载是CGI性能低下的主要原因。FastCGI只是一个接口。
FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。多数流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,同时,FastCGI也被许多脚本语言所支持,其中就有PHP。
FastCGI是从CGI发展改进而来的。传统CGI接口方式的主要缺点是性能很差,因为每次HTTP服务器遇到动态程序时都需要重新启动脚本解析器来执行解析,然后结果被返回给HTTP服务器。这在处理高并发访问时,几乎是不可用的。另外传统的CGI接口方式安全性也很差,现在已经很少被使用了。
FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
FastCGI的工作原理(以PHP来说明)?
(1). FastCGI进程管理器自身初始化,启动多个CGI解释器进程(多个php-cgi进程)并等待来自Web Server的连接。PHP-FPM进程管理器启动多个php-cgi FastCGI进程。启动php-cgi FastCGI进程时,可以配置以TCP和UNIX套接字两种方式启动。
(2). 当客户端请求到达Web服务器(Nginx)时,Web服务器将请求采用TCP协议或UNIX套接字方式转发到FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器(子进程)。Web服务器将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
(3). FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web服务器(如nginx)。当FastCGI子进程关闭连接时,请求便可告知处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器的下一个连接。而在一般的普通CGI模式中,php-cgi在此便退出了(可以想象普通的CGI模式多慢,每个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重新初始化全部数据结构。)使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是:持续数据库连接可以工作。
Nginx+FastCGI运行原理?
Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket,(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接纳到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整个运作过程。下面是调用流程图:
PHP FastCGI的优点:
(1). PHP脚本运行速度更快。PHP解释程序被载入内存而不用每次需要时从存储器读取,此举极大提升了依靠脚本运行站点的性能。
(2). 需要使用的系统资源更少。由于服务器不用在每次需要时都载入PHP解释程序,你可以将站点的传输速度提升很多而不必增加CPU负担。
(3). FastCGI 的主要优点是把动态语言和HTTP Server分离开来,所以Nginx与PHP/PHP-FPM经常被部署在不同的服务器上,以分担前端Nginx服务器的压力,使Nginx专一处理静态请求和转发动态请求,而PHP/PHP-FPM服务器专一解析PHP动态请求。
1.2 lnmp的安装
http://blog.51niux.com/?id=39 #已经记录了lnmp的安装过程,虽然版本比较老了吧,可以将软件包换成新的包组,安装新软件。安装过程没啥变化。
1.3 nginx的配置支持PHP
由于Nginx本身不会对PHP进行解析,因此要实现Nginx对PHP的支持,其实是将对PHP页面的请求交给fastCGI进程监听的IP地址及端口。如果把php-fpm当做动态应用服务器,那么Nginx其实就是一个反向代理服务器。Nginx通过反向代理功能实现对PHP的解析,这就是Nginx实现PHP动态解析的原理。
location ~ \.php$ { #匹配所有php结尾的请求 root html; fastcgi_index index.php; #如果URI以斜线结尾,文件名将追加到URI后面,这个值将存储在变量$fastcgi_script_name中,在这里指定fastcgi_index 其实是没有用的,因为前面的location ~* \.php$已经把“/结束”这种情况排除了 fastcgi_pass 127.0.0.1:9000; #指明nginx与fastcgi交互的IP和端口号,也就是fastcgi监听的端口 #fastcgi_pass unix:/var/run/php-fpm.sock; #这是nginx与fastcgi通过unix交互的形式,一般不这么用。 include fastcgi_params; #这里是包含所有nginx常量,传递给php-cgi。 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #脚本文件请求的路径 #fastcgi_param QUERY_STRING $query_string; #请求的参数;如?app=123 #fastcgi_param REMOTE_ADDR $remote_addr; #客户端IP }
下面是FastCGI的一些优化指令,将下面代码添加到Nginx主配置文件中的HTTP层级。(一般也不做这些参数的优化,这里就是记录一下)
fastcgi_connect_timeout 300; #指定连接到后端FastCGI的超时时间 fastcgi_send_timeout 300; #指定向FastCGI传送请求的超时时间,这个值是已经完成两次握手后向FastCGI传送请求的超时时间 fastcgi_read_timeout 300; #指定接收FastCGI应答的超时时间,这个值是已经完成两次握手后接收DastCGI应答的超时时间 fastcgi_buffer_size 64k; #用于指定读取FastCGI应答第一部分需要用多大的缓冲区,这个值表示将使用1个64KB的缓冲区读取应答的第一部分(应答头),可以设置为可以设置为fastcgi_buffers选项指定的缓冲区大小 fastcgi_buffers 4 64k; #指定本地需要用多少和多大的缓冲区来缓冲FastCGI的应答请求。如果一个PHP脚本所产生的页面大小为256KB,那么会为其分配4个64KB的缓冲区来缓存; 如果页面大小大于256KB,那么大于256KB的部分会缓存到fastcgi_temp指定的路径中,但是这并不是好方法,因为内存中的数据处理速度要快于硬盘。一般这个值应该为站点中PHP脚本所产生的页面大小的中间值,如果站点大部分脚本所产生的页面大小为256KB,那么可以把这个值设置为“16 16k”、“4 64k”等。 fastcgi_busy_buffers_size 128k; #fastcgi_busy_buffers_size的默认值是fastcgi_buffers的两倍。 fastcgi_temp_file_write_size 128k; #表示在写入缓存文件时使用多大的数据块,默认值是fastcgi_buffers的两倍。
博文来自:www.51niux.com
1.4 再次来记录一下Nginx+php+fastcgi的原理与关系
先了解下php-fpm:
php-fpm,即专门为php打造的fastCGI process manager(PHP的fastCGI管理器)。nginx使用这些php-fpm进程来和PHP进行通信,你可以理解把php-fpm理解为php解释器。
和传统的php-cgi的解释器不同,php-fpm实现了fastCGI协议,而且还新增了不少特性。比如php-fpm能够平滑重启php环境配置:我们知道在修改了php.ini之后,wamp和phpstudy需要重启服务器才能重新加载php.ini里的内容。如果是php-fpm,则不用重启web服务器,原先正在工作的php-fpm继续工作,等原先工作的php-fpm完成自己的工作后,就结束掉自己。
fastCGI的工作方式:
第一次启动时,会启动一个php-fpm的master进程,该master进程初始化环境后,启动多个worker进程(即php-fpm进程池中的php-fpm),如下图:
当请求发来后,master进程把请求分发到进程池中的php-fpm,分发完后,就可以接下一个请求了,避免了重复劳动(重复加载php.ini初始化环境),效率提升。当请求多的时候,master会启动更多的php-fpm子进程,当请求少的时候,master也会停掉一些子进程。既提高了性能,也节省资源。
当然,当php-fpm设定的上限,不足以支持更高的并发请求时,nginx只能返回502错误了,因为没有更多的php-fpm进程可用了。在这种协议下,php-fpm成为了和PHP沟通的PHP解释器。
nginx与php-fpm进程交流:
为了能够使 Nginx 理解 fastcgi 协议,Nginx 提供了 fastcgi 模块来将 http 请求映射为对应的 fastcgi 请求。
# cat /usr/local/nginx/conf/fastcgi_params #用来把nginx中的变量,解释为PHP能够理解的变量
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
# cat /usr/local/nginx/conf/nginx.conf #nginx把php请求交给fastCGI模块来处理的配置
location ~ \.php$ { root html; fastcgi_index index.php; fastcgi_pass 127.0.0.1:9000; include fastcgi_params; }
当有一个web请求访问过来的时候,先是到达nginx,然后nginx判断其是一个动态请求还是一个静态请求,如果是请求jpg,或者html等之类的不需要用到php去处理的请求,直接就返回结果了。如果是指定了要php处理的,nginx会通过fastcgi_pass将用户请求的资源发给127.0.0.1:9000进行解析,这里的nginx和php脚本解析服务器是在同一台机器上,所以127.0.0.1:9000表示的就是本地的php脚本解析服务器,也就是通过fastcgi_pass将用户的请求发送给php-fpm。然后php的master进程会把请求交给php-fpm进程池的一个worker,然后处理完毕后php将查询后的结果返回给nginx,然后nginx再将结果返回给用户。
博文来自:www.51niux.com
二、nginx反向代理与负载均衡
2.1 反向代理介绍
反向代理(Reverse Proxy)是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络对Internet的连接请求,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就变现为一个服务器。
通常的代理服务器,只用于代理内部网络对于Internet的连接请求,客户机必须制定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。这是正向代理,后面会介绍。
代理外部网络上的主机访问代理服务器不支持外部对内部网络的访问请求,这种代理服务的方式称为反向代理服务。此时代理服务器对外就表现为一个Web服务器,外部网络就可以简单把它当做一个标准的Web服务器而不需要特定的配置。这个反向代理服务器没有保存任何网页的真实数据,所有的静态网页或CGI程序,都保存在内部的Web服务器上。
2.2 负载均衡介绍
负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求根据指定的算法分配到指定的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。随着业务不断拓展、用户量的增加,原来的一台nginx代理服务器已经很吃力了,所以需要对后台服务器做负载均衡,提高并发能力。
2.3 nginx反向代理的例子
如生产上我们除了php以外,还有tomcat啊resin啊这些java程序,机器或在本机或者在其他机器上面,这时候就需要利用nginx的反向代理功能了。
client_header_buffer_size 32k; #这三个值前面已经介绍过了,这三个要定义在http区域中,下方那些proxy优化内容除了proxy_pass一般也定义在http全局中。 client_max_body_size 200m; #这个可以定义在location区域中 large_client_header_buffers 4 32k; location ~ (\.jsp)|(\.do)$ { #这是一种方式,另一种方式是跟负载均衡的方式一起使用的形式。 proxy_pass http://192.168.1.102:8080; #如果做了动静分离机器,动态程序可能部署在了其他机器上面,就不能使用127.0.0.1了,如果是多机器的话就要用到负载均衡了 proxy_buffer_size 32k; #默认值是4k/8k,该指令设置缓冲区大小,从代理后端服务器取得的第一部分的响应内容,会放到这里. proxy_buffering on; #默认就是on。该指令开启从后端被代理服务器的响应内容缓冲.如果缓冲区开启,nginx假定被代理的后端服务器会以最快速度响应,并把内容保存在由指令proxy_buffer_size 和 proxy_buffers指定的缓冲区里边. 如果响应内容无法放在内存里边,那么部分内容会被写到磁盘上。如果缓冲区被关闭了,那么响应内容会按照获取内容的多少立刻同步传送到客户端。nginx不尝试计算被代理服务器整个响应内容的大小,nginx能从服务器接受的最大数据,是由指令proxy_buffer_size指定的. 对于基于长轮询(long-polling)的Comet 应用来说,关闭 proxy_buffering 是重要的,不然异步响应将被缓存导致Comet无法工作 proxy_buffers 8 32k; #默认值是8 4k/8k。该指令设置缓冲区的大小和数量,从被代理的后端服务器取得的响应内容,会放置到这里. 默认情况下,一个缓冲区的大小等于内存页面大小,可能是4K也可能是8K,这取决于平台。 proxy_busy_buffers_size 64k; #如果系统很忙的时候可以申请更大的proxy_buffers官网推荐*2. #上面proxy_buffer_size 64k;proxy_buffers 4 32k; proxy_busy_buffers_size 64k;为了解决后端服务器传输数据header过大的问题。 proxy_temp_file_write_size 64k; #proxy临时文件的大小 proxy_ignore_client_abort on; #默认 proxy_ignore_client_abort 是关闭的,此时在请求过程中如果客户端端主动关闭请求或者客户端网络断掉,那么 Nginx 会记录 499,同时 request_time 是 「后端已经处理」的时间,而 upstream_response_time 为 “-“ 。 那么客户端主动断掉连接之后,Nginx 会等待后端处理完(或者超时),然后 记录 「后端的返回信息」 到日志。所以,如果后端 返回 200, 就记录 200 ;如果后端放回 5XX ,那么就记录 5XX 。如果超时(默认60s,可以用 proxy_read_timeout 设置),Nginx 会主动断开连接,记录 504 。 proxy_connect_timeout 60; #默认值就是60s,该指令设置与upstream server的连接超时时间,有必要记住,这个超时不能超过75秒。这个不是等待后端返回页面的时间,那是由proxy_read_timeout声明的。 如果你的upstream服务器起来了,但是hanging住了(例如,没有足够的线程处理请求,所以把你的请求放到请求池里稍后处理),那么这个声明是没有用的,由于与upstream服务器的连接已经建立了。 proxy_read_timeout 600; #连接成功后等待后端服务器响应时间,其实已经进入后端的排队之中等候处理。 proxy_send_timeout 600; #后幅服务器数据回传时间,就是在规定时间内后端服务器必须传完所有的数据。 proxy_redirect off; #语法:proxy_redirect [ default|off|redirect replacement ],默认值是default。如果使用“default”参数,将根据location和proxy_pass参数的设置来决定。如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,可以用这个指令设置。 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #上面三个参数就是为了将真实的来源IP传递给后端实际提供服务的服务器,不然后端机器log里面记录的是反向代理的IP地址。proxy_set_header允许重新定义或添加字段传递给代理服务器的请求头。该值可以包含文本、变量和它们的组合。在没有定义proxy_set_header时会继承之前定义的值。 #proxy_set_header 就是可设置请求头-并将头信息传递到服务器端。不属于请求头的参数中也需要传递时 重定义下就行。 }
buffer工作原理:
首先第一个概念是所有的这些proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。
proxy_buffering是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。
无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。
一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。
2.5 nginx负载均衡的upstream模块
Upstream模块是Nginx负载均衡的主要模块,它提供了一个简单方法来实现再轮询和客户端IP之间的后端服务器负载均衡,并可以对后端服务器进行健康检查。
ip_hash指令:
默认值是none。
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。
使用ip_hash指令无法保证后端服务器的负载均衡,可能有些后端服务器接收到的请求多,有些后端服务器接收到的请求少,而且设置后端服务器权重等方法将不起作用。所以,如果后端的动态应用服务器能够做到SESSION共享,不过现在一般后端会通过memcached之类的做session共享,当然如果简单设置的话也可以采用nfs的session共享方式来代替nginx的ip_hash方式。
如果后端服务器有时要从nginx负载均衡(已使用ip_hash)中摘除一段时间,你必须将其标记为"down",而不是直接从配置文件中删除或注释掉后端服务器的信息。
server指令:
默认值是none。该指令用于指定后端服务器的名称和参数。服务器的名称可以是一个域名、一个IP地址、端口号或UNIX Socket。
在后端服务器名称之后,可以跟一下参数:
weight=数字 : 设置服务器的权重,权重数值越高,被分配到的客户端请求数越多。如果没有设置权重,默认权重为1.
max_fails = 数字 :在参数fail_timeout指定的时间内对后端服务器请求失败的次数,如果检测到后端服务器无法连接及发送服务器错误(404错误除外),则标记为失败。如果没有设置则为默认值1.设置数值0将关闭这项检查。
fail_timeout=时间 : 在经历参数max_fails设置的失败次数后,暂停的时间。
down:标记服务器为永久离线状态,用于ip_hash指令。
backup:仅仅在非backup服务器全部宕机或繁忙的时候才启用。
注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。
upstream指令:
默认值是none。该指令用于设置一组可以在proxy_pass和fastcgi_pass指令中使用的代理服务器,默认的负载均衡方式为轮询。
upstream 支持的负载均衡算法:
轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
fair:这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
url_hash:此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。
upstream相关变量:
从nginx 0.5.18版本开始,可以支持用log_format指令设置日志格式,日志格式中可以使用下面变量(upstream模块拥有以下变量):
$upstream_addr:处理请求的upstream服务器地址。
$upstream_status:upstream服务器的应答状态。
$upstream_response_tine:upstream服务器相应时间(毫秒)。
$upstream_http_$HEADER : 任意的HTTP协议头信息,例如:$upstream_http_host
2.6 nginx的UploadProgressModule模块
NginxUploadProgressModule介绍:
Nginx提供了NginxUploadProgressModule模块,用来处理文件上传的进度它不是nginx内置的模块,编译时需要加上一下选项–add-module=../nginx_uploadprogress_module。
当nginx用作前端的proxy时,它默认会把当前request body的值给缓存到client_body_buffer_size或临时文件中,当client完成上传后,nginx才会把文件给push到后端的server,所以,没有办法从后端的服务器上来获得正确的进度信息,必须在前端的nginx上来配置upload选项。
原理是:nginx作为代理服务,在代理到后端服务之前,将请求内容全部缓存到磁盘上,通过每次上传的一个唯一标识,能够获取当前服务器已经接收的大小。
nginx upload模块指令集:
upload_progress :
语法:upload_progress <zone_name> <zone_size>;
作用:声名nginx server使用upload progress module,引用名为zone_name,并分配zone_size bytes的空间存放上传状态信息
track_uploads :
语法:track_uploads <zone_name> <timeout>;
作用:声名此location使用upload_progress模块记录文件上传,这条指令必须位于location配置的最后。
report_uploads:
语法:report_uploads <zone_name>
作用:允许一个location响应上传状态,响应内容默认为一个javascript的new object语句对象,有四种状态响应:
上传开始(准备中或者请求未到达):new Object({"state":"starting"})
正在上传:new Object({"state":"uploading","received":<size_received>,"size":<total_size>})
上传完成:new Object({"state":"done"})
上传错误:new Object({"state":"error","status":<error code>})
upload_progress_content_type:
语法:upload_progress_content_type <content-type>
作用:状态响应的content-type,默认为test/javascript,即可执行的javascript代码
upload_progress_header:
语法:upload_progress_header <progress-id>
作用:修改标识上传ID的参数(header)名,默认为X-Progress-ID
upload_progress_jsonp_parameter:
语法:upload_progress_jsonp_parameter <callback_parameter>
作用:修改jsonp形式的callback函数名,默认值为“callback”
upload_progress_json_output:
语法:upload_progress_json_output
作用:声名响应输出为json格式
upload_progress_jsonp_output:
语法:upload_progress_jsonp_output
作用:声名响应输出为jsonp格式
upload_progress_template:
语法:upload_progress_template <state> <template>
state可选:starting、uploading、error、done
模板中可渲染变量:$uploadprogress_length、$uploadprogress_received、$uploadprogress_status、$uploadprogress_callback
在使用该模块时,一点需要注意以下问题:
track_uploads必须是location中最后一个指令,比如:它必须要放在proxy_pass的后边。
如果通过X-Progress-ID的get参数来获取进度信息,则它必须是url中最后一个参数,如:/progress?user=test&X-Progress-ID=123456 必须设置client_max_body_size,它的值需要大于单次上传的最大值
示例:
http{ ... upload_progress 51niux_space_upload 10m; #开启上传进度,使用8M空间存储每个连接的进度信息,为这个引用设置了一个名称叫做51niux_space_upload upstream music_upload_51niux_space { #定义了一个叫做backend_51niux_space的upstream server 127.0.0.1:8107; #将请求转交给本地的8107端口,可见这是nginx将动态请求转交给了本地的动态程序一般是Java程序之类的。 keepalive 64; #nginx与后端服务器的连接时间。Nginx1.1.14版本以前与后端upstream服务器建立的都是短链接,即通过HTTP/1.0向后端发起连接,并把请求的"Connection" header设为"close"。HTTP协议中对长连接的支持是从1.1版本之后才有的。这里根据自己需求设置。 } ... server { listen 80; server_name music.51niux.com; charset UTF-8; ... location ^~ /51niux_space/upload/ { #当匹配到此upload的location的时候 proxy_pass http://music_upload_51niux_space; #将此请求交给music_upload_51niux_space里面定义的server主机 client_max_body_size 100m; #文件最大为100MB track_uploads 51niux_space_upload 5m; #此url需要跟踪进度信息,该信息在上传完成后会保留5分钟,如果是30秒就是30s。 } }
博文来自:www.51niux.com
2.7 nginx的upstream示例
示例1(指定权重轮询):
http{ ... upstream api_51niux_servers { #定义了一个叫做api_51niux_servers的upstream,里面有三台主机,不过他们的权重一样,所以就是正常的轮询。如果谁性能好一点可以把数字加大,多分配点任务给这台机器。 server 192.168.1.102:8106 weight=5; #每个请求按时间顺序逐一分配到不同的后端服务器,如果超过了最大失败次数后(max_fails,默认1),在失效时间内(fail_timeout,默认10秒),该节点失效权重变为0,超过失效时间后,则恢复正常,或者全部节点都为down后,那么将所有节点都恢复为有效继续探测,一般来说rr可以根据权重来进行均匀分配。 server 192.168.1.103:8106 weight=5; #可以自定义max_fails和fail_timeout,如server 192.168.1.103:8106 weight=5 max_fails=2 fail_timeout=30s; server 192.168.1.104:8106 weight=5; keepalive 64; } ... server { listen 80; server_name api.51niux.com; charset UTF-8; access_log logs/api.51niux.com.access.log main; location / { proxy_pass http://api_51niux_servers ; #这里就是通过proxy_pass进行转发,把关于api.51niux.com域名的请求转发给 api_51niux_servers这个upstream下面的主机来处理。 } } ... }
示例2(ip_hash负载均衡):
http下: upstream backend_51niux_event { ip_hash; #这里指定引用了ip_hash的算法。也是nginx自带的负载均衡。每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题,但是ip_hash会造成负载不均,有的服务请求接受多,有的服务请求接受少。 server 192.168.1.105:8016; server 192.168.1.106:8016; #如果有某台服务器不可用,你必须标记其为"down".如:server 192.168.1.106:8016 down; } service下: location /event { proxy_pass http://backend_51niux_event; }
示例3(基于perl的一致性哈希):
降低 后端大文件服务器由于新增和故障调整的影响通过nginx的perl_module来实现302,根据请求的哈希跳转crc32校验。
工作环境: perl版本在>=5.10.0 nginx版本 >==0.8.33 二点必要
#cat /usr/local/nginx/conf/rewrite.pm
package rewrite; use nginx; use Hash::ConsistentHash; use String::CRC32; use LWP::UserAgent; my @data_51niux = ( "192.168.1.102:80", #当然也可以设置成域名的形式,如:"bj151.data.51niux.com:80" "192.168.1.103:80", "192.168.1.104:80" ); sub host_handler { my $r = shift; my @hosts = @_; my $uri = $r->uri; my $domain = $r->header_in(host); my $hash_key = $uri; my $host = hash_select(\@hosts, $hash_key); my $url = "http://".$host.$uri.$r->variable("is_args").$r->variable("args"); $r->header_out(Location => $url); $r->header_out("X-File-Host" => $host); $r->status(302); $r->send_http_header; return OK; } sub handler_data { my $r = shift; return host_handler( $r, @data_51niux ); } 1; __END__
nginx server配置:
location ~ \.(mp3|wma|mp4|flv)$ { valid_referers none blocked *.51niux.com ; set $valid_access 0; if ($invalid_referer != '1'){ set $valid_access 1; } if ( $http_cookie ~* "^have"){ #这是如果cookie匹配上,当然也可以if ( $http_cookie ~* "(.*)$") {set $all_cookie $1;} #获取所有的cookie信息。或者if ( $http_cookie ~* "pass_ip=(.+)(?:;|$)" ) {set $one_cookie $1;} #提取指定的一个cookie的值 set $valid_access 1; } if ($valid_access = 0) { return 403; } perl rewrite::handler_data; expires 1d; }
nginx http的全局配置:
perl_modules conf; perl_require rewrite.pm;
另外:
Fair(第三方)负载均衡模式:
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
lurl_hash(第三方)负载均衡模式:
和ip_hash算法类似,是对每个请求按url的hash结果分配,使每个URL定向到一个同 一个后端服务器,但是也会造成分配不均的问题,这种模式后端服务器为缓存时比较好。
另外:
proxy_http_version 1.1; #为了让nginx和后端server(nginx称为upstream)之间保持长连接,典型设置如下:(默认nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接)
proxy_set_header Connection ""; #是清理从client过来的http header,因为即使是client和nginx之间是短连接,nginx和upstream之间也是可以开启长连接的。这种情况下必须清理来自client请求中的”Connection” header。
如果做为一个websocket反向代理下面的设置:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; #nginx正常只能代理http请求,如果想实现代理websocket的需求,需在请求中加入"Upgrade"字段,使请求从http升级为websocket。 proxy_set_header Connection "upgrade";
proxy_next_upstream error timeout http_500 http_404;
#语法: proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]
确定在何种情况下请求将转发到下一个服务器。转发请求只发生在没有数据传递到客户端的过程中。
#在nginx配置反向代理时,此配置对客户体验影响较大,当客户端请求一个不存在的文件,导致较长时间才能返回请求失败,虽然在真实的环境中有一定的冗余作用,如不善用弊大于利!
#当设定proxy_next_upstream http_404,并且upstream里配置是max_fails=0,则访问到不存在文件时,将会有死循环现象,nginx负载明显升高,kill -HUP进程消逝很慢。同样的,proxy_next_upstream如果设定为其它值,例如http_503、invalid_header等也会有同样问题,但默认的error timeout不会出问题。