重庆企业网站制作外包,logo制作器,网页空间的利用要,oa系统手机端上一篇《WEB请求处理一#xff1a;浏览器请求发起处理》#xff0c;我们讲述了浏览器端请求发起过程#xff0c;通过DNS域名解析服务器IP#xff0c;并建立TCP连接#xff0c;发送HTTP请求。本文将讲述请求到达反向代理服务器的一个处理过程#xff0c;比如#xff1a;在…上一篇《WEB请求处理一浏览器请求发起处理》我们讲述了浏览器端请求发起过程通过DNS域名解析服务器IP并建立TCP连接发送HTTP请求。本文将讲述请求到达反向代理服务器的一个处理过程比如在Nginx中请求的反向代理处理流程请求都是经过了哪些模块做了哪些处理又是如何找到应用服务器呢
为直观明了先上一张图红色部分为本章所述模块 本章所述模块
正如标题所述Nginx功能是进行请求的反向代理在讲解Nginx请求处理之前首先要给大家清楚地说明下反向代理是什么它的功能是什么它在Nginx中又是怎么配置实现的
1 反向代理#
1.1 概念##
反向代理Reverse Proxy方式是指以代理服务器来接受internet上的连接请求然后将请求转发给内部网络上的服务器并将从服务器上得到的结果返回给internet上请求连接的客户端此时代理服务器对外就表现为一个服务器。
举个例子比如我想访问 http://www.test.com/readme 但www.test.com上并不存在readme页面于是他是偷偷从另外一台服务器上取回来然后作为自己的内容返回用户但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能。
结论就是反向代理服务器对于客户端而言它就像是原始服务器并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求接着反向代理服务器将判断向何处(原始服务器)转交请求并将获得的内容返回给客户端就像这些内容原本就是它自己的一样。
正向代理既然有反向代理就肯定有正向代理。什么叫正向代理呢
正向代理Forward Proxy通常都被简称为代理就是在用户无法正常访问外部资源比方说受到GFW的影响无法访问twitter的时候我们可以通过代理的方式让用户绕过防火墙从而连接到目标网络或者服务。
正向代理的工作原理就像一个跳板比如我访问不了google.com但是我能访问一个代理服务器AA能访问google.com于是我先连上代理服务器A告诉他我需要google.com的内容A就去取回来然后返回给我。从网站的角度只在代理服务器来取内容的时候有一次记录有时候并不知道是用户的请求也隐藏了用户的资料这取决于代理告不告诉网站。
结论就是正向代理是一个位于客户端和原始服务器(origin server)之间的服务器。为了从原始服务器取得内容客户端向代理发送一个请求并指定目标(原始服务器)然后代理向原始服务器转交请求并将获得的内容返回给客户端。
反向代理VS正向代理 反向代理VS正向代理
1.2 工作流程## 用户通过域名发出访问Web服务器的请求该域名被DNS服务器解析为反向代理服务器的IP地址 反向代理服务器接受用户的请求 反向代理服务器在本地缓存中查找请求的内容找到后直接把内容发送给用户 如果本地缓存里没有用户所请求的信息内容反向代理服务器会代替用户向源服务器请求同样的信息内容并把信息内容发给用户如果信息内容是缓存的还会把它保存到缓存中。 1.3 优点##
保护了真实的web服务器web服务器对外不可见外网只能看到反向代理服务器而反向代理服务器上并没有真实数据因此保证了web服务器的资源安全
通常的代理服务器只用于代理内部网络对Internet外部网络的连接请求客户机必须指定代理服务器并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。不支持外部网络对内部网络的连接请求因为内部网络对外部网络是不可见的。当一个代理服务器能够代理外部网络上的主机访问内部网络时这种代理服务的方式称为反向代理服务。此时代理服务器对外就表现为一个Web服务器外部网络就可以简单把它当作一个标准的Web服务器而不需要特定的配置。不同之处在于这个服务器没有保存任何网页的真实数据所有的静态网页或者CGI程序都保存在内部的Web服务器上。因此对反向代理服务器的攻击并不会使得网页信息遭到破坏这样就增强了Web服务器的安全性。
代理服务器充当内容服务器的替身如果您的内容服务器具有必须保持安全的敏感信息如信用卡号数据库可在防火墙外部设置一个代理服务器作为内容服务器的替身。当外部客户机尝试访问内容服务器时会将其送到代理服务器。实际内容位于内容服务器上在防火墙内部受到安全保护。代理服务器位于防火墙外部在客户机看来就像是内容服务器。
当客户机向站点提出请求时请求将转到代理服务器。然后代理服务器通过防火墙中的特定通路将客户机的请求发送到内容服务器。内容服务器再通过该通道将结果回传给代理服务器。代理服务器将检索到的信息发送给客户机好像代理服务器就是实际的内容服务器。如果内容服务器返回错误消息代理服务器会先行截取该消息并更改标头中列出的任何URL然后再将消息发送给客户机。如此可防止外部客户机获取内部内容服务器的重定向URL。
这样代理服务器就在安全数据库和可能的恶意攻击之间提供了又一道屏障。与有权访问整个数据库的情况相对比就算是侥幸攻击成功作恶者充其量也仅限于访问单个事务中所涉及的信息。未经授权的用户无法访问到真正的内容服务器因为防火墙通路只允许代理服务器有权进行访问。
可以配置防火墙路由器使其只允许特定端口上的特定服务器有权通过防火墙进行访问而不允许其他任何机器进出。安全反向代理指当代理服务器与其他机器之间有一个或多个连接使用安全套接字层 (SSL) 协议加密数据时即会进行安全反向代理。
节约了有限的IP地址资源
企业内所有的网站共享一个在internet中注册的IP地址这些服务器分配私有地址采用虚拟主机的方式对外提供服务。
减少WEB服务器压力提高响应速度
反向代理就是通常所说的web服务器加速它是一种通过在繁忙的web服务器和外部网络之间增加一个高速的web缓冲服务器来降低实际的web服务器的负载的一种技术。反向代理是针对web服务器提高加速功能作为代理缓存它并不是针对浏览器用户而针对一台或多台特定的web服务器它可以代理外部网络对内部网络的访问请求。
反向代理服务器会强制将外部网络对要代理的服务器的访问经过它这样反向代理服务器负责接收客户端的请求然后到源服务器上获取内容把内容返回给用户并把内容保存到本地以便日后再收到同样的信息请求时它会把本地缓存里的内容直接发给用户以减少后端web服务器的压力提高响应速度。因此Nginx还具有缓存功能。
其他优点1请求的统一控制包括设置权限、过滤规则等 2区分动态和静态可缓存内容 3实现负载均衡内部可以采用多台服务器来组成服务器集群外部还是可以采用一个地址访问 4解决Ajax跨域问题 5作为真实服务器的缓冲解决瞬间负载量大的问题 2 Nginx常用配置#
写到这时一直在由于要不要去开这一节Nginx配置的讲解如果讲的话感觉与本文的主题有所偏离但又考虑到如果对Nginx配置文件都不熟悉的话下面的内容再去讲解Nginx反向代理处理流程就有点纸上谈兵了担心大家有些云里雾里毫无收获。
终究旨在为了要让大家有所收获的初衷决定还是要着重讲解Nginx的几种常见配置其中包括动静分离、缓存设置、负载均衡、反向代理、还有虚拟主机功能。
2.1 Nginx启动和关闭##
Mac平台我用brew安装的
/usr/local/bin/nginx # 启动
/usr/local/bin/nginx -s reload #平滑重启
/usr/local/etc/nginx/nginx.cnf #配置文件。2.2 配置文件详解##
其实对比apache的配置文件它的相对比较清晰和简单之前觉得很难现在沉下心来想想其实很简单。大致的分块下基本就分为以下几块
main # 全局设置
events { # Nginx工作模式....
}
http { # http设置....upstream myproject { # 负载均衡服务器设置.....}server { # 主机设置....location { # URL匹配....}}server {....location {....}}....
}2.2.1 main模块###
下面是一个main区域它是一个全局的设置
user nobody nobody;
worker_processes 2;
error_log /usr/local/var/log/nginx/error.log notice;
pid /usr/local/var/run/nginx/nginx.pid;
worker_rlimit_nofile 1024;user 来指定Nginx Worker进程运行用户以及用户组默认由nobody账号运行。 worker_processes 来指定了Nginx要开启的子进程数。每个Nginx进程平均耗费10M~12M内存。根据经验一般指定1个进程就足够了如果是多核CPU建议指定和CPU的数量一样的进程数即可。我这里写2那么就会开启2个子进程总共3个进程。 error_log 来定义全局错误日志文件。日志输出级别有debug、info、notice、warn、error、crit可供选择其中debug输出日志最为最详细而crit输出日志最少。 pid 来指定进程id的存储文件位置。 worker_rlimit_nofile 来指定一个nginx进程可以打开的最多文件描述符数目这里是65535需要使用命令“ulimit -n 65535”来设置。 2.2.2 events模块###
events模块来用指定nginx的工作模式和工作模式及连接数上限一般是这样
events {use kqueue; #mac平台worker_connections 1024;
}use 用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式kqueue和epoll是高效的工作模式不同的是epoll用在Linux平台上而kqueue用在BSD系统中因为Mac基于BSD,所以Mac也得用这个模式对于Linux系统epoll工作模式是首选。 worker_connections 用于定义Nginx每个进程的最大连接数即接收前端的最大请求数默认是1024。最大客户端连接数由worker_processes和worker_connections决定即Max_clients worker_processes * worker_connections在作为反向代理时Max_clients变为Max_clients worker_processes * worker_connections / 4。 进程的最大连接数受Linux系统进程的最大打开文件数限制在执行操作系统命令“ulimit -n 65536”后worker_connections的设置才能生效。 2.2.3 http模块###
http模块可以说是最核心的模块了它负责HTTP服务器相关属性的配置它里面的server和upstream子模块至关重要等到反向代理和负载均衡以及虚拟目录等会仔细说。
http {include mime.types;default_type application/octet-stream;log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for;access_log /usr/local/var/log/nginx/access.log main;sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 10;#gzip on;upstream myproject {.....}server {....}
}include用来设定文件的mime类型,类型在配置文件目录下的mime.type文件定义来告诉nginx来识别文件类型。 default_type设定了默认的类型为二进制流也就是当文件类型未定义时使用这种方式例如在没有配置asp的locate 环境时Nginx是不予解析的此时用浏览器访问asp文件就会出现下载窗口了。 log_format用于设置日志的格式和记录哪些参数这里设置为main刚好用于access_log来纪录这种类型。 main的类型日志如下也可以增删部分参数。 127.0.0.1 - - [21/Apr/2015:18:09:54 0800] GET /index.php HTTP/1.1 200 87151 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36 access_log用来纪录每次的访问日志的文件地址后面的main是日志的格式样式对应于log_format的main。 sendfile用于开启高效文件传输模式。将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞。 keepalive_timeout设置客户端连接保持活动的超时时间。在超过这个时间之后服务器会关闭该连接。 2.2.4 server模块###
server模块是http的子模块它用来定一个虚拟主机我们先讲最基本的配置这些在后面再讲。我们看一下一个简单的server是如何做的
server {listen 8080;server_name localhost 192.168.12.10 www.yangyi.com;# 全局定义如果都是这一个目录这样定义最简单。root /Users/yangyi/www;index index.php index.html index.htm; charset utf-8;access_log usr/local/var/log/host.access.log main;error_log usr/local/var/log/host.error.log error;....
}server 标志定义虚拟主机开始。 listen 用于指定虚拟主机的服务端口。 server_name 用来指定IP地址或者域名多个域名之间用空格分开。 root 表示在这整个server虚拟主机内全部的root web根目录。注意要和locate {}下面定义的区分开来。 index 全局定义访问的默认首页地址。注意要和locate {}下面定义的区分开来。 charset 用于设置网页的默认编码格式。 access_log 用来指定此虚拟主机的访问日志存放路径最后的main用于指定访问日志的输出格式。 2.2.5 location模块###
location模块是nginx中用的最多的也是最重要的模块了什么负载均衡啊、反向代理啊、虚拟域名啊都与它相关。
location根据它字面意思就知道是来定位的定位URL解析URL所以它也提供了强大的正则匹配功能也支持条件判断匹配用户可以通过location指令实现Nginx对动、静态网页进行过滤处理。像我们的php环境搭建就是用到了它。
我们先来看这个设定默认首页和虚拟机目录
location / {root /Users/yangyi/www;index index.php index.html index.htm;
}location / 表示匹配访问根目录。 root 指令用于指定访问根目录时虚拟主机的web目录这个目录可以是相对路径相对路径是相对于nginx的安装目录。也可以是绝对路径。 index 用于设定我们只输入域名后访问的默认首页地址有个先后顺序index.php index.html index.htm如果没有开启目录浏览权限又找不到这些默认首页就会报403错误。 location 还有一种方式就是正则匹配开启正则匹配这样location 。后面加个
下面这个例子是运用正则匹配来链接php。我们之前搭建环境也是这样做
location ~ \.php$ {root /Users/yangyi/www;fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;include fastcgi.conf;
}.php$ 熟悉正则的我们直到这是匹配.php结尾的URL用来解析php文件。里面的root也是一样用来表示虚拟主机的根目录。 fastcgi_pass 链接的是php-fpm的地址。其他几个参数我们以后再说。 location 还有其他用法等讲到实例的时候再看吧。 2.2.6 upstream模块###
upstream 模块负责负载均衡模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。先学习怎么用具体的使用实例以后再说。
upstream iyangyi.com{ip_hash;server 192.168.12.1:80;server 192.168.12.2:80 down;server 192.168.12.3:8080 max_fails3 fail_timeout20s;server 192.168.12.4:8080;
}在上面的例子中通过upstream指令指定了一个负载均衡器的名称iyangyi.com。这个名称可以任意指定在后面需要的地方直接调用即可。里面是ip_hash这是其中的一种负载均衡调度算法下面会着重介绍。紧接着就是各种服务器了。用server关键字表识后面接ip。
Nginx的负载均衡模块目前支持4种调度算法 weight 轮询默认。每个请求按时间顺序逐一分配到不同的后端服务器如果后端某台服务器宕机故障系统被自动剔除使用户访问不受影响。weight。指定轮询权值weight值越大分配到的访问机率越高主要用于后端每个服务器性能不均的情况下。 ip_hash。每个请求按访问IP的hash结果分配这样来自同一个IP的访客固定访问一个后端服务器有效解决了动态网页存在的session共享问题。 fair第三方。比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡也就是根据后端服务器的响应时间来分配请求响应时间短的优先分配。Nginx本身是不支持fair的如果需要使用这种调度算法必须下载Nginx的upstream_fair模块。 url_hash第三方。按访问url的hash结果来分配请求使每个url定向到同一个后端服务器可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的如果需要使用这种调度算法必须安装Nginx的hash软件包。 在HTTP Upstream模块中可以通过server指令指定后端服务器的IP地址和端口同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有 down表示当前的server暂时不参与负载均衡。 backup预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候才会请求backup机器因此这台机器的压力最轻。 max_fails允许请求失败的次数默认为1。当超过最大次数时返回proxy_next_upstream 模块定义的错误。 fail_timeout在经历了max_fails次失败后暂停服务的时间。max_fails可以和fail_timeout一起使用。 注意当负载调度算法为ip_hash时后端服务器在负载均衡调度中的状态不能是weight和backup。
2.3 基于域名的虚拟主机##
假设我们在本地开发有3个项目分别在hosts里映射到本地的127.0.0.1上
127.0.0.1 www.iyangyi.com iyangyi.com
127.0.0.1 api.iyangyi.com
127.0.0.1 admin.iyangyi.com有这样3个项目分别对应于web根目录下的3个文件夹我们用域名对应文件夹名字这样子好记
/Users/yangyi/www/www.iyangyi.com/
/Users/yangyi/www/api.iyangyi.com/
/Users/yangyi/www/admin.iyangyi.com/每个目录下都有一个index.php文件都是简单的输入自己的域名。
下面我们就来搭建这3个域名的虚拟主机很显然我们要新建3个server来完成。建议将对虚拟主机进行配置的内容写进另外一个文件然后通过include指令包含进来这样更便于维护和管理。不会使得这个nginx.conf内容太多
main
events {....
}
http {....include vhost/www.iyangyi.conf;include vhost/api.iyangyi.conf;include vhost/admin.iyangyi.conf;# 或者用 *.conf 包含# include vhost/*.conf
}include主模块指令实现对配置文件所包含的文件的设定可以减少主配置文件的复杂度。
既然每一个conf都是一个server前面已经学习了一个完整的server写的了。下面就开始
# www.iyangyi.conf
server {listen 80;server_name www.iyangyi.com iyangyi.com;root /Users/yangyi/www/www.iyangyi.com/;index index.php index.html index.htm;access_log /usr/local/var/log/nginx/www.iyangyi.access.log main;error_log /usr/local/var/log/nginx/www.iyangyi.error.log error;location ~ \.php$ {fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php;include fastcgi.conf;}
}# api.iyangyi.conf
server {listen 80;server_name api.iyangyi.com;root /Users/yangyi/www/api.iyangyi.com/;index index.php index.html index.htm;access_log /usr/local/var/log/nginx/api.iyangyi.access.log main;error_log /usr/local/var/log/nginx/api.iyangyi.error.log error;location ~ \.php$ {fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php;include fastcgi.conf;}
}# admin.iyangyi.conf
server {listen 80;server_name admin.iyangyi.com;root /Users/yangyi/www/admin.iyangyi.com/;index index.php index.html index.htm;access_log /usr/local/var/log/nginx/admin.iyangyi.access.log main;error_log /usr/local/var/log/nginx/admin.iyangyi.error.log error;location ~ \.php$ {fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php;include fastcgi.conf;}
}这样3个很精简的虚拟域名就搭建好了。重启下nginx然后打开浏览器访问一下这3个域名就能看到对应的域名内容了。
2.4 反向代理##
Nginx 使用反向代理主要是使用location模块下的proxy_pass选项。
来个最简单的。当我访问 mac 上的nginx 的 centos.iyangyi.com 的内容时候, 就反向代理到虚拟机centos上的 apache 192.168.33.10 的index.html页面。
192.168.33.10 中的html 是很简单的一句输出
centos apache2 index.html在hosts里新加上这个域名
#vi /etc/hosts
127.0.0.1 centos.iyangyi.com在vhost目录中新建一个conf server
#centos.iyangyi.conf
server {listen 80;server_name centos.iyangyi.com;access_log /usr/local/var/log/nginx/centos.iyangyi.access.log main;error_log /usr/local/var/log/nginx/centos.iyangyi.error.log error;location / {proxy_pass http://192.168.33.10;}
}重启下nginx
sudo nginx -s reload当然。proxy 还有其他的参数比如proxy_set_header 用来设置header头部信息参数转发等等用了可以仔细看看。
2.5 负载均衡##
别被这个名字给吓住了以为是什么很牛逼的东西的。其实不然。也很简单。
先简单说下负载均衡是干嘛的举个例子我们的小网站刚开始就一台nginx服务器后来随着业务量增大用户增多一台服务器已经不够用了我们就又多加了几台服务器。那么这几台服务器如何调度如何均匀的提供访问这就是负载均衡。
负载均衡的好处是可以集群多台机器一起工作并且对外的IP和域名是一样的外界看起来就好像一台机器一样。
基于 weight 权重的负载
先来一个最简单的weight权重的
upstream webservers{server 192.168.33.11 weight10;server 192.168.33.12 weight10;server 192.168.33.13 weight10;
}server {listen 80;server_name upstream.iyangyi.com;access_log /usr/local/var/log/nginx/upstream.iyangyi.access.log main;error_log /usr/local/var/log/nginx/upstream.iyangyi.error.log error;location / {proxy_pass http://webservers;proxy_set_header X-Real-IP $remote_addr;}
}我们再来继续看几个参数 : max_fails和fail_timeout **max_fails : **允许请求失败的次数默认为1。当超过最大次数时返回proxy_next_upstream 模块定义的错误。 **fail_timeout : **在经历了max_fails次失败后暂停服务的时间。max_fails可以和fail_timeout一起使用进行健康状态检查。 upstream webservers{server 192.168.33.11 weight10 max_fails2 fail_timeout30s;server 192.168.33.12 weight10 max_fails2 fail_timeout30s;server 192.168.33.13 weight10 max_fails2 fail_timeout30s;
}down 表示这台机器暂时不参与负载均衡。相当于注释掉了。 backup 表示这台机器是备用机器是其他的机器不能用的时候这台机器才会被使用俗称备胎 upstream webservers{server 192.168.33.11 down;server 192.168.33.12 weight10 max_fails2 fail_timeout30s;server 192.168.33.13 backup;
}基于 ip_hash 的负载
这种分配方式每个请求按访问IP的hash结果分配这样来自同一个IP的访客固定访问一个后端服务器有效解决了动态网页存在的session共享问题。
upstream webservers{ip_hash;server 192.168.33.11 weight1 max_fails2 fail_timeout30s;server 192.168.33.12 weight1 max_fails2 fail_timeout30s;server 192.168.33.13 down;
}ip_hash 模式下最好不要设置weight参数因为你设置了就相当于手动设置了将会导致很多的流量分配不均匀。 ip_hash 模式下backup参数不可用加了会报错为啥呢因为本身我们的访问就是固定的了其实备用已经不管什么作用了。 2.6 页面缓存##
页面缓存也是日常web 开发中很重要的一个环节对于一些页面我们可以将其静态化保存起来下次请求时候直接走缓存而不用去请求反相代理服务器甚至数据库服务了。从而减轻服务器压力。
nginx 也提供了简单而强大的下重定向反向代理的缓存功能只需要简单配置下就能将指定的一个页面缓存起来。它的原理也很简单就是匹配当前访问的url, hash加密后去指定的缓存目录找看有没有有的话就说明匹配到缓存了。
我们先来看一下一个简单的页面缓存的配置
http {proxy_cache_path /data/nginx/cache levels1:2 keys_zonecache_zone:10m inactive1d max_size100m;upstream myproject {.....}server {....location ~ *\.php$ {proxy_cache cache_zone; #keys_zone的名字proxy_cache_key $host$uri$is_args$args; #缓存规则proxy_cache_valid any 1d;proxy_pass http://127.0.0.1:8080;}}....
}下面我们来一步一步说。用到的配置参数主要是proxy_*前缀的很多配置。
首先需要在http中加入proxy_cache_path 它用来制定缓存的目录以及缓存目录深度制定等。它的格式如下
proxy_cache_path path [levelsnumber] keys_zonezone_name:zone_size [inactivetime] [max_sizesize]; path是用来指定 缓存在磁盘的路径地址。比如/data/nginx/cache。那以后生存的缓存文件就会存在这个目录下。 levels用来指定缓存文件夹的级数可以是levels1, levels1:1, levels1:2, levels1:2:3 可以使用任意的1位或2位数字作为目录结构分割符如 X, X:X,或 X:X:X 例如: 2, 2:2, 1:1:2但是最多只能是三级目录。 那这个里面的数字是什么意思呢。表示取hash值的个数。比如 现在根据请求地址localhost/index.php?a4 用md5进行哈希得到e0bd86606797639426a92306b1b98ad9 levels1:2 表示建立2级目录把hash最后1位(9)拿出建一个目录然后再把9前面的2位(ad)拿来建一个目录, 那么缓存文件的路径就是/data/nginx/cache/9/ad/e0bd86606797639426a92306b1b98ad9 以此类推levels1:1:2表示建立3级目录把hash最后1位(9)拿出建一个目录然后再把9前面的1位(d)建一个目录, 最后把d前面的2位(8a)拿出来建一个目录 那么缓存文件的路径就是/data/nginx/cache/9/d/8a/e0bd86606797639426a92306b1b98ad9 keys_zone 所有活动的key和元数据存储在共享的内存池中这个区域用keys_zone参数指定。zone_name指的是共享池的名称zone_size指的是共享池的大小。注意每一个定义的内存池必须是不重复的路径例如
proxy_cache_path /data/nginx/cache/one levels1 keys_zoneone:10m;
proxy_cache_path /data/nginx/cache/two levels2:2 keys_zonetwo:100m;
proxy_cache_path /data/nginx/cache/three levels1:1:2 keys_zonethree:1000m;inactive 表示指定的时间内缓存的数据没有被请求则被删除默认inactive为10分钟。inactive1d 1天。inactive30m 30分钟。 max_size 表示单个文件最大不超过的大小。它被用来删除不活动的缓存和控制缓存大小当目前缓存的值超出max_size指定的值之后超过其大小后最少使用数据LRU替换算法将被删除。max_size10g表示当缓存池超过10g就会清除不常用的缓存文件。 clean_time 表示每间隔自动清除的时间。clean_time1m 1分钟清除一次缓存。 好。说完了这个很重要的参数。我们再来说在server模块里的几个配置参数 proxy_cache 用来指定用哪个keys_zone的名字也就是用哪个目录下的缓存。上面我们指定了三个one, two,three 。比如我现在想用one 这个缓存目录 : proxy_cache one proxy_cache_key 这个其实蛮重要的它用来指定生成hash的url地址的格式。根据这个key映射成一个hash值然后存入到本地文件。proxy_cache_key $host$uri表示无论后面跟的什么参数都会访问一个文件不会再生成新的文件。 而如果proxy_cache_key $is_args$args那么传入的参数 localhost/index.php?a4 与localhost/index.php?a44 将映射成两个不同hash值的文件。 proxy_cache_key 默认是 $scheme$host$request_uri。但是一般我们会把它设置成$host$uri$is_args$args 一个完整的url路径。 proxy_cache_valid 它是用来为不同的http响应状态码设置不同的缓存时间。 proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;表示为http status code 为200和302的设置缓存时间为10分钟404代码缓存1分钟。 如果只定义时间
proxy_cache_valid 5m;那么只对代码为200, 301和302的code进行缓存。 同样可以使用any参数任何相响应
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m; #所有的状态都缓存1小时好。缓存的基本一些配置讲完了。也大致知道了怎么使用这些参数。现在开始实战我们启动一台vagrant linux 机器 web1 (192.168.33.11) 用作远程代理机器就不搞复杂的负载均衡了。
先在Mac本地加一个域名cache.iyangyi.com, 然后按照上面的配置在vhost 下新建一个proxy_cache.iyangyi.conf 文件:
proxy_cache_path /usr/local/var/cache levels1:2 keys_zonecache_zone:10m inactive1d max_size100m;
server {listen 80;server_name cache.iyangyi.com;access_log /usr/local/var/log/nginx/cache.iyangyi.access.log main;error_log /usr/local/var/log/nginx/cache.iyangyi.error.log error;add_header X-Via $server_addr;add_header X-Cache $upstream_cache_status;location / {proxy_set_header X-Real-IP $remote_addr;proxy_cache cache_zone;proxy_cache_key $host$uri$is_args$args;proxy_cache_valid 200 304 1m;proxy_pass http://192.168.33.11;}
}打开审核元素或者firebug。看network网络请求选项我们可以看到Response Headers在这里我们可以看到
X-Cache:MISS
X-Via:127.0.0.1X-cache 为 MISS 表示未命中请求被传送到后端。因为是第一次访问没有缓存所以肯定是未命中。我们再刷新下就发现其变成了HIT, 表示命中。它还有其他几种状态 MISS 未命中请求被传送到后端 HIT 缓存命中 EXPIRED 缓存已经过期请求被传送到后端 UPDATING 正在更新缓存将使用旧的应答 STALE 后端将得到过期的应答 BYPASS 缓存被绕过了 我们再去看看缓存文件夹 /usr/local/var/cache里面是否有了文件
cache git:(master) cd a/13
➜ 13 git:(master) ls
5bd1af99bcb0db45c8bd601d9ee9e13a
➜ 13 git:(master) pwd
/usr/local/var/cache/a/13已经生成了缓存文件。
我们在url 后面随便加一个什么参数看会不会新生成一个缓存文件夹及文件http://cache.iyangyi.com/?www55 。因为我们使用的生成规则是全部url转换(proxy_cache_key $host$uri$is_args$args;)
查看 X-cache 为 MISS再刷新 变成HIT。再去看一下缓存文件夹 /usr/local/var/cache。
~cache git:(master) ls4 a果然又生成了一个4文件夹。
2.7 location 正则模块##
这一小节主要来学习nginx中的URL重写怎么做。url重写模块主要是在location模块面来实现我们一点一点的看。
首先看下location 正则匹配的使用。还记得之前是如何用location来定位.php文件的吗?
location ~ \.php$ {fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php;include fastcgi.conf;
}我们用~来表示location开启正则匹配, 这样location ~。还可以用这个来匹配静态资源缓存它们设置过期时间
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|mp3|mp4|swf){expires 15d;
}
location ~ .*\.(css|js){expires 12h;
}expires 用来设置HTTP应答中的Expires和Cache-Control的头标时间来告诉浏览器访问这个静态文件时不用再去请求服务器直接从本地缓存读取就可以了。 语法 expires [time|epoch|max|off]
默认值 expires off
作用域 http, server, location可以在time值中使用正数或负数。“Expires”头标的值将通过当前系统时间加上您设定的 time 值来获得。可以设置的参数如下 epoch 指定“Expires”的值为 1 January, 1970, 00:00:01 GMT。 max 指定“Expires”的值为 31 December 2037 23:59:59 GMT“Cache-Control”的值为10年。 -1 指定“Expires”的值为 服务器当前时间 -1s,即永远过期。 负数Cache-Control: no-cache。 正数或零Cache-Control: max-age #, # 会转换为指定时间的秒数。比如1d、2h、3m。 off 表示不修改“Expires”和“Cache-Control”的值。 比如再看个例子: 控制图片等过期时间为30天
location ~ \.(gif|jpg|jpeg|png|bmp|ico)$ {expires 30d;
}我们还可以控制哪一个文件目录的时间比如控制匹配/resource/或者/mediatorModule/里所有的文件缓存设置到最长时间。
location ~ /(resource|mediatorModule)/ {root /opt/demo;expires max;
}2.8 URL重写模块##
重写模块与很多模块一起使用。先看一下是怎么用的看2个例子然后我们再一点一点讲每个的使用方法
location /download/ {if ($forbidden) {return 403;}if ($slow) {limit_rate 10k;}rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;......
}location / {root html;index index.html index.htm;rewrite ^/bbs/(.*)$ http://192.168.18.201/forum/$1;
}上面2个例子就是利用rewrite来完成URL重写的。我们慢慢来看它的用法。
break
break和编程语言中的用法一样就是跳出某个逻辑。 语法break 默认值none 使用字段server, location, if if (!-f $request_filename) {break;
}上面这个例子就是在if里面使用break,意思是如果访问的文件名不存在就跳出。后续会有更多的例子。
if
if 判断一个条件如果条件成立则后面的大括号内的语句将执行相关配置从上级继承。 语法if (condition) { … } 默认值none 使用字段server, location 可以在判断语句中指定下列值 一个变量的名称不成立的值为空字符传”“或者一些用“0”开始的字符串。 一个使用或者!运算符的比较语句。 使用符号*和模式匹配的正则表达式 ~为区分大小写的匹配。 ~*不区分大小写的匹配firefox匹配FireFox。 !和!*意为“不匹配的”。 使用-f和!-f检查一个文件是否存在。 使用-d和!-d检查一个目录是否存在。 使用-e和!-e检查一个文件目录或者软链接是否存在。 使用-x和!-x检查一个文件是否为可执行文件。 $http_user_agent变量获取浏览器的agent使用~ 来匹配大小写。用户如果使用的IE 浏览器就执行if里面的操作。
if ($http_user_agent ~ MSIE) {rewrite ^(.*)$ /msie/$1 break;
}$request_method变量获取请求的方法使用来判断是否等于POST 。如果复合就执行if 里面的操作。
if ($request_method POST ) {return 405;
}$request_filename变量获取请求的文件名使用!-f来匹配文件如果不是一个文件名就执行if 里面的逻辑。
if (!-f $request_filename) {break;proxy_pass http://127.0.0.1;
}return
这个指令结束执行配置语句并为客户端返回状态代码可以使用下列的值204400402-406408410, 411, 413, 416与500-504。此外非标准代码444将关闭连接并且不发送任何的头部。 语法return code 默认值none 使用字段server, location, if rewrite语法rewrite regex replacement flag 默认值none 使用字段server, location, if rewrite用来重写url,有3个位置 regex 表示用来匹配的正则 replacement 表示用来替换的 flag 是尾部的标记 flag可以是以下的值 last - url重写后马上发起一个新的请求再次进入server块重试location匹配超过10次匹配不到报500错误地址栏url不变 break - url重写后直接使用当前资源不再执行location里余下的语句完成本次请求地址栏url不变 redirect - 返回302临时重定向url会跳转爬虫不会更新url。 permanent - 返回301永久重定向。url会跳转。爬虫会更新url。 为空 - URL 不会变但是内容已经变化也是永久性的重定向。 上面的正则表达式的一部分可以用圆括号方便之后按照顺序用$1-$9来引用。
我们来看几个例子 需要将/photos/123456重写成/path/to/photos/12/1234/123456.png 可以这样
rewrite /photos/([0-9] {2})([0-9] {2})([0-9] {2}) /path/to/photos/$1/$1$2/$1$2$3.png;下面是一些简单的常见的重写
rewrite ^/js/base.core.v3.js /js/base.core.v3.dev.js redirect;
rewrite ^/js/comment.frame.js /js/comment.frame.dev.js redirect;
rewrite ^/live-static/(.*)$ http://live.bilibili.com/public/$1 last;2.9 配置整理##
在此记录下Nginx服务器nginx.conf的配置文件说明, 部分注释收集与网络
# 运行用户
user www-data;
# 启动进程,通常设置成和cpu的数量相等
worker_processes 1;# 全局错误日志及PID文件
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;# 工作模式及连接数上限
events {use epoll; #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能worker_connections 1024; #单个后台worker process进程的最大并发链接数# multi_accept on;
}#设定http服务器利用它的反向代理功能提供负载均衡支持
http {#设定mime类型,类型由mime.type文件定义include /etc/nginx/mime.types;default_type application/octet-stream;#设定日志格式access_log /var/log/nginx/access.log;#sendfile 指令指定 nginx 是否调用 sendfile 函数zero copy 方式来输出文件对于普通应用#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用可设置为 off以平衡磁盘与网络I/O处理速度降低系统的uptime.sendfile on;#将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞tcp_nopush on;tcp_nodelay on;#连接超时时间keepalive_timeout 65;#开启gzip压缩gzip on;gzip_disable MSIE [1-6]\.(?!.*SV1);#设定请求缓冲client_header_buffer_size 1k;large_client_header_buffers 4 4k;include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;#设定负载均衡的服务器列表upstream mysvr {#weigth参数表示权值权值越高被分配到的几率越大#本机上的Squid开启3128端口server 192.168.8.1:3128 weight5;server 192.168.8.2:80 weight1;server 192.168.8.3:80 weight6;}server {#侦听80端口listen 80;#定义使用www.xx.com访问server_name www.xx.com;#设定本虚拟主机的访问日志access_log logs/www.xx.com.access.log main;#默认请求location / {root /root; #定义服务器的默认网站根目录位置index index.php index.html index.htm; #定义首页索引文件的名称fastcgi_pass www.xx.com;fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include /etc/nginx/fastcgi_params;}# 定义错误提示页面error_page 500 502 503 504 /50x.html; location /50x.html {root /root;}#静态文件nginx自己处理location ~ ^/(images|javascript|js|css|flash|media|static)/ {root /var/www/virtual/htdocs;#过期30天静态文件不怎么更新过期可以设大一点如果频繁更新则可以设置得小一点。expires 30d;}#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.location ~ \.php$ {root /root;fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME /home/www/www$fastcgi_script_name;include fastcgi_params;}#设定查看Nginx状态的地址location /NginxStatus {stub_status on;access_log on;auth_basic NginxStatus;auth_basic_user_file conf/htpasswd;}#禁止访问 .htxxx 文件location ~ /\.ht {deny all;}}#第一个虚拟服务器server {#侦听192.168.8.x的80端口listen 80;server_name 192.168.8.x;#对aspx后缀的进行负载均衡请求location ~ .*\.aspx$ {root /root;#定义服务器的默认网站根目录位置index index.php index.html index.htm;#定义首页索引文件的名称proxy_pass http://mysvr;#请求转向mysvr 定义的服务器列表#以下是一些反向代理的配置可删除.proxy_redirect off;#后端的Web服务器可以通过X-Forwarded-For获取用户真实IPproxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;client_max_body_size 10m; #允许客户端请求的最大单文件字节数client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)proxy_read_timeout 90; #连接成功后后端服务器响应时间(代理接收超时)proxy_buffer_size 4k; #设置代理服务器nginx保存用户头信息的缓冲区大小proxy_buffers 4 32k; #proxy_buffers缓冲区网页平均在32k以下的话这样设置proxy_busy_buffers_size 64k; #高负荷下缓冲大小proxy_buffers*2proxy_temp_file_write_size 64k; #设定缓存文件夹大小大于这个值将从upstream服务器传}}
}3 Nginx模块#
上面我们已经详细讲解了Nginx常用配置从中我们已经体会到了Nginx模块化配置的优点。其中模块化设计类似于面向对象中的接口类它增强了nginx源码的可读性、可扩充性和可维护性。
所以Nginx有五大优点模块化、事件驱动、异步、非阻塞、多进程单线程。由内核和模块组成的其中内核完成的工作比较简单仅仅通过查找配置文件将客户端请求映射到一个location block然后又将这个location block中所配置的每个指令将会启动不同的模块去完成相应的工作。
3.1 模块划分##
Nginx的模块从结构上分为核心模块、基础模块和第三方模块 核心模块HTTP模块、EVENT模块和MAIL模块 基础模块HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块 第三方模块HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。 Nginx的模块从功能上分为如下三类 Core(核心模块)构建nginx基础服务、管理其他模块。 Handlers处理器模块此类模块直接处理请求并进行输出内容和修改headers信息等操作。Handlers处理器模块一般只能有一个。 Filters 过滤器模块此类模块主要对其他处理器模块输出的内容进行修改操作最后由Nginx输出。 Proxies 代理类模块此类模块是Nginx的HTTP Upstream之类的模块这些模块主要与后端一些服务比如FastCGI等进行交互实现服务代理和负载均衡等功能。 Nginx的核心模块主要负责建立nginx服务模型、管理网络层和应用层协议、以及启动针对特定应用的一系列候选模块。其他模块负责分配给web服务器的实际工作 (1) 当Nginx发送文件或者转发请求到其他服务器由Handlers(处理模块)或Proxies代理类模块提供服务 (2) 当需要Nginx把输出压缩或者在服务端加一些东西由Filters(过滤模块)提供服务。 3.2 模块处理##
当服务器启动每个handlers(处理模块)都有机会映射到配置文件中定义的特定位置location如果有多个handlers(处理模块)映射到特定位置时只有一个会“赢”说明配置文件有冲突项应该避免发生。
处理模块以三种形式返回 OK ERROR 或者放弃处理这个请求而让默认处理模块来处理主要是用来处理一些静态文件事实上如果是位置正确而真实的静态文件默认的处理模块会抢先处理。 如果handlers(处理模块)把请求反向代理到后端的服务器就变成另外一类的模块load-balancers负载均衡模块。负载均衡模块的配置中有一组后端服务器当一个HTTP请求过来时它决定哪台服务器应当获得这个请求。
Nginx的负载均衡模块采用两种方法 轮转法它处理请求就像纸牌游戏一样从头到尾分发 IP哈希法在众多请求的情况下它确保来自同一个IP的请求会分发到相同的后端服务器。 如果handlers(处理模块)没有产生错误filters过滤模块将被调用。多个filters过滤模块能映射到每个位置所以比如每个请求都可以被压缩成块。它们的执行顺序在编译时决定。
filters过滤模块是经典的“接力链表CHAIN OF RESPONSIBILITY”模型一个filters过滤模块被调用完成其工作然后调用下一个filters过滤模块直到最后一个filters过滤模块。
过滤模块链的特别之处在于 每个filters过滤模块不会等上一个filters过滤模块全部完成 它能把前一个过滤模块的输出作为其处理内容有点像Unix中的流水线 过滤模块能以buffer缓冲区为单位进行操作这些buffer一般都是一页4K大小当然你也可以在nginx.conf文件中进行配置。这意味着比如模块可以压缩来自后端服务器的响应然后像流一样的到达客户端直到整个响应发送完成。
总之过滤模块链以流水线的方式高效率地向客户端发送响应信息。
所以总结下上面的内容一个典型的HTTP处理周期是这样的客户端发送HTTP请求 – Nginx基于配置文件中的位置选择一个合适的处理模块 - (如果有)负载均衡模块选择一台后端服务器 – 处理模块进行处理并把输出缓冲放到第一个过滤模块上 – 第一个过滤模块处理后输出给第二个过滤模块 – 然后第二个过滤模块又到第三个 – 依此类推 – 最后把响应发给客户端。 下图展示了Nginx模块处理流程 Nginx模块处理流程
Nginx本身做的工作实际很少当它接到一个HTTP请求时它仅仅是通过查找配置文件将此次请求映射到一个location block而此location中所配置的各个指令则会启动不同的模块去完成工作因此模块可以看做Nginx真正的劳动工作者。通常一个location中的指令会涉及一个handler模块和多个filter模块当然多个location可以复用同一个模块。handler模块负责处理请求完成响应内容的生成而filter模块对响应内容进行处理。
4 Nginx请求处理#
Nginx在启动时会以daemon形式在后台运行采用多进程异步非阻塞IO事件模型来处理各种连接请求。多进程模型包括一个master进程多个worker进程一般worker进程个数是根据服务器CPU核数来决定的。master进程负责管理Nginx本身和其他worker进程。如下图 Master进程负责管理Nginx本身和其他worker进程 从上图中可以很明显地看到4个worker进程的父进程都是master进程表明worker进程都是从父进程fork出来的并且父进程的ppid为1表示其为daemon进程。 需要说明的是在nginx多进程中每个worker都是平等的因此每个进程处理外部请求的机会权重都是一致的。 Nginx架构及工作流程图 Nginx架构及工作流程图
Nginx的每一个Worker进程都管理着大量的线程真正处理请求业务的是Worker之下的线程。worker进程中有一个ngx_worker_process_cycle()函数执行无限循环不断处理收到的来自客户端的请求并进行处理直到整个Nginx服务被停止。
worker 进程中ngx_worker_process_cycle()函数就是这个无限循环的处理函数。在这个函数中一个请求的简单处理流程如下 操作系统提供的机制例如 epoll, kqueue 等产生相关的事件。 接收和处理这些事件如是接收到数据则产生更高层的 request 对象。 处理 request 的 header 和 body。 产生响应并发送回客户端。 完成 request 的处理。 重新初始化定时器及其他事件。 4.1 多进程处理模型##
下面来介绍一个请求进来多进程模型的处理方式 首先master进程一开始就会根据我们的配置来建立需要listen的网络socket fd然后fork出多个worker进程。 其次根据进程的特性新建立的worker进程也会和master进程一样具有相同的设置。因此其也会去监听相同ip端口的套接字socket fd。 然后这个时候有多个worker进程都在监听同样设置的socket fd意味着当有一个请求进来的时候所有的worker都会感知到。这样就会产生所谓的“惊群现象”。为了保证只会有一个进程成功注册到listenfd的读事件nginx中实现了一个“accept_mutex”类似互斥锁只有获取到这个锁的进程才可以去注册读事件。其他进程全部accept 失败。 最后监听成功的worker进程读取请求解析处理响应数据返回给客户端断开连接结束。因此一个request请求只需要worker进程就可以完成。 进程模型的处理方式带来的一些好处就是进程之间是独立的也就是一个worker进程出现异常退出其他worker进程是不会受到影响的此外独立进程也会避免一些不需要的锁操作这样子会提高处理效率并且开发调试也更容易。
如前文所述多进程模型异步非阻塞模型才是胜出的方案。单纯的多进程模型会导致连接并发数量的降低而采用异步非阻塞IO模型很好的解决了这个问题并且还因此避免的多线程的上下文切换导致的性能损失。
worker进程会竞争监听客户端的连接请求这种方式可能会带来一个问题就是可能所有的请求都被一个worker进程给竞争获取了导致其他进程都比较空闲而某一个进程会处于忙碌的状态这种状态可能还会导致无法及时响应连接而丢弃discard掉本有能力处理的请求。这种不公平的现象是需要避免的尤其是在高可靠web服务器环境下。
针对这种现象Nginx采用了一个是否打开accept_mutex选项的值ngx_accept_disabled标识控制一个worker进程是否需要去竞争获取accept_mutex选项进而获取accept事件。 ngx_accept_disabled值nginx单进程的所有连接总数的八分之一减去剩下的空闲连接数量得到的这个ngx_accept_disabled。 当ngx_accept_disabled大于0时不会去尝试获取accept_mutex锁并且将ngx_accept_disabled减1于是每次执行到此处时都会去减1直到小于0。不去获取accept_mutex锁就是等于让出获取连接的机会很显然可以看出当空闲连接越少时ngx_accept_disable越大于是让出的机会就越多这样其它进程获取锁的机会也就越大。不去accept自己的连接就控制下来了其它进程的连接池就会得到利用这样nginx就控制了多进程间连接的平衡了。 4.2 一个简单的HTTP请求##
从 Nginx 的内部来看一个 HTTP Request 的处理过程涉及到以下几个阶段 初始化 HTTP Request读取来自客户端的数据生成 HTTP Request 对象该对象含有该请求所有的信息。 处理请求头。 处理请求体。 如果有的话调用与此请求URL 或者 Location关联的 handler。 依次调用各 phase handler 进行处理。 在建立连接过程中对于nginx监听到的每个客户端连接都会将它的读事件的handler设置为ngx_http_init_request函数这个函数就是请求处理的入口。在处理请求时主要就是要解析http请求比如uri请求行等然后再根据请求生成响应。下面看一下nginx处理的具体过程 Nginx处理的具体过程
在这里我们需要了解一下 phase handler 这个概念。phase 字面的意思就是阶段。所以 phase handlers 也就好理解了就是包含若干个处理阶段的一些 handler。
在每一个阶段包含有若干个 handler再处理到某个阶段的时候依次调用该阶段的 handler 对 HTTP Request 进行处理。
通常情况下一个 phase handler 对这个 request 进行处理并产生一些输出。通常 phase handler 是与定义在配置文件中的某个 location 相关联的。
一个 phase handler 通常执行以下几项任务 获取 location 配置。 产生适当的响应。 发送 response header。 发送 response body。 当 Nginx 读取到一个 HTTP Request 的 header 的时候Nginx 首先查找与这个请求关联的虚拟主机的配置。如果找到了这个虚拟主机的配置那么通常情况下这个 HTTP Request 将会经过以下几个阶段的处理phase handlers NGX_HTTP_POST_READ_PHASE: 读取请求内容阶段 NGX_HTTP_SERVER_REWRITE_PHASE: Server 请求地址重写阶段 NGX_HTTP_FIND_CONFIG_PHASE: 配置查找阶段 NGX_HTTP_REWRITE_PHASE: Location请求地址重写阶段 NGX_HTTP_POST_REWRITE_PHASE: 请求地址重写提交阶段 NGX_HTTP_PREACCESS_PHASE: 访问权限检查准备阶段 NGX_HTTP_ACCESS_PHASE: 访问权限检查阶段 NGX_HTTP_POST_ACCESS_PHASE: 访问权限检查提交阶段 NGX_HTTP_TRY_FILES_PHASE: 配置项 try_files 处理阶段 NGX_HTTP_CONTENT_PHASE: 内容产生阶段 NGX_HTTP_LOG_PHASE: 日志模块处理阶段 在内容产生阶段为了给一个 request 产生正确的响应Nginx 必须把这个 request 交给一个合适的 content handler 去处理。如果这个 request 对应的 location 在配置文件中被明确指定了一个 content handler那么Nginx 就可以通过对 location 的匹配直接找到这个对应的 handler并把这个 request 交给这个 content handler 去处理。这样的配置指令包括像perlflvproxy_passmp4等。
如果一个 request 对应的 location 并没有直接有配置的 content handler那么 Nginx 依次尝试 如果一个 location 里面有配置 random_index on那么随机选择一个文件发送给客户端。 如果一个 location 里面有配置 index 指令那么发送 index 指令指明的文件给客户端。 如果一个 location 里面有配置 autoindex on那么就发送请求地址对应的服务端路径下的文件列表给客户端。 如果这个 request 对应的 location 上有设置 gzip_static on那么就查找是否有对应的.gz文件存在有的话就发送这个给客户端客户端支持 gzip 的情况下。 请求的 URI 如果对应一个静态文件static module 就发送静态文件的内容到客户端。 内容产生阶段完成以后生成的输出会被传递到 filter 模块去进行处理。filter 模块也是与 location 相关的。所有的 fiter 模块都被组织成一条链。输出会依次穿越所有的 filter直到有一个 filter 模块的返回值表明已经处理完成。
这里列举几个常见的 filter 模块例如 server-side includes。 XSLT filtering。 图像缩放之类的。 gzip 压缩。 在所有的 filter 中有几个 filter 模块需要关注一下。按照调用的顺序依次说明如下 copy: 将一些需要复制的 buf(文件或者内存)重新复制一份然后交给剩余的 body filter 处理。 postpone: 这个 filter 是负责 subrequest 的也就是子请求的。 write: 写输出到客户端实际上是写到连接对应的 socket 上。 4.3 请求完整处理过程##
根据以上请求步骤所述请求完整的处理过程如下图所示 请求完整的处理过程
转自https://www.jianshu.com/p/bed000e1830b