nginx反向代理及负载均衡

基于Nginx反向代理及负载均衡php

只要没有被启用,默认就是开启的,由于proxy属于nginx内置标准模块,一般实现代理的时候,最核心模块是proxy_pass,用于将用户请求的rui递交至上游服务器的某个URI但这个模块大部分用于location当中,所以要实现将某一URI的访问代理某个上游服务器大体的格式为:css

location /name/ {html

proxy_pass http://127.0.0.1/remote/;前端

}node

参数解释:nginx

location /name/ 指定当前服务器server的某一访问路径,原本这个location中定义的是root或其余相关参数,今后这个 location不在本地提供任何服务,而是经过proxy_pass模块传至远程其余主机http://127.0.0.1/remote/上去web

其中/name/ 和 /remote/ 能够是不相匹配的, nginx能够自动处理这种映射关系。express

但须要注意的是,当定义location的时候,其必须有一个转换关系,意为咱们当前主机的路径uri要转换另外服务器的uri,这是其对应关系,事实上目标主机的uri能够省略掉,可是一旦省略掉就表示不将其转换apache

示例:vim

location/some/path/ {

proxy_pass http://127.0.0.1;#这里只有ip地址,后面没有任何uri

}

例:

nginx-->web

如图所示当咱们请求nginx某个uri的时候,nginx自动的代理至web服务器中,它并不真正提供用户请求的内容而仅仅的将用户的请求接进来,而且代理用户去web服务器上去取数据

一般web服务器会记录日志的,那么这时访问日志中远程ip则是nginx的ip地址

对于一个web服务器来说记录的全部的ip地址都是代理服务器的,那么咱们在某些分析的层面来说是没有意义的,因此一般在这类场景下一般须要在nginx服务上作一些简单修改,而且在后端服务器上也作一些修改用于记录真实的客户端IP地址

将请求在nginx转发至后端主机的时候在头部加入header信息

参考:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_header

实现反向代理

IP地址       服务器角色

10.0.10.61 Nginx 实现反向代理

10.0.10.83 Apache上游服务器

10.0.10.82 Apache上游服务器

启动后端apache 服务

[root@mode local]#/usr/local/apache/bin/apachectl start

[root@mode test]# echo'<h1>10.0.10.83</h1>' > index.html

[root@modephp_test]# curl localhost  
<h1>10.0.10.83</h1>

咱们指望用户访问某个路径的时候,来源的路径是后端服务器的:

咱们只要建一个新的location就能够了,以下所示

新创建location,明确说明使用proxy_pass模块代理后端主机10.0.10.83

       location /test {  
            proxy_pass http://10.0.10.83/; #注意一旦带有斜线就表示有url的若是没有url必定不能带斜线,这就表示访问的test没错,可是将test映射至后端主机,但后端并无test目录    
        }

检查语法是否正确并从新加载配置文件

[root@node1 nginx]#/usr/local/nginx/sbin/nginx -t  
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok    
nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@node1 nginx]#/etc/init.d/nginx reload

使用curl访问测试http://10.0.10.61/test

[root@node1 nginx]#curl http://10.0.10.61/test/

<h1>10.0.10.83</h1>

咱们再来查看后端apache的访问日志

[root@modetest_php]# tail access_w_20140508.log

10.0.10.61 - -[08/May/2014:11:04:38 +0800] "GET / HTTP/1.0" 304 - "-""Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/34.0.1847.131 Safari/537.36"

10.0.10.61 - - [08/May/2014:11:04:38+0800] "GET / HTTP/1.0" 304 - "-" "Mozilla/5.0(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/34.0.1847.131 Safari/537.36"

能够看到来源地址都是nginx服务器的地址,对于咱们以后分析日志没有任何意义所在,因此那这个时候咱们想换成客户端地址必须借助于proxy_set_header模块

实现显示真实客户端IP

proxy_set_header模块使用示例

       location /test {  
            proxy_passhttp://10.0.10.83/;    
proxy_set_header X-Real-IP $remote_addr;    
        }

proxy_set_header表示将发送至upsream server的报文的某首部进行重写;

X-Real-IP 表示 hader的名称为X-Real-IP

传递给X-Real-IP的地址是$remote_addr

再来查看后端日志的访问ip,不管怎么刷新它的记录ip依旧仍是nginx

由于后端的服务器只记录了client值,并无记录咱们定义的header的值,因此咱们还须要对apache的日志参数作修改

编辑httpd.conf,定义日志格式

[root@mode conf]#vim httpd.conf

将其注释并复制

#LogFormat "%h%l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""combined

将%h改成"%{X-Real-ip}i

LogFormat "%{X-Real-IP}i %l %u %t \"%r\"%>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

%h是表示远端客户的ip地址,这里咱们将其改为某个特定首部的值也就是刚才我定义的X-Real-IP,而引用特定首部的值的格式是%{xxx}i这样就表示引用这个首部的值

保存退出并从新加载apache

[root@mode conf]#/usr/local/apache/bin/apachectl graceful

再次访问并查看日志

已看到目前已记录客户端的真实IP地址

[root@modetest_php]# tail -1 access_w_20140508.log

10.0.10.1- - [08/May/2014:12:44:40 +0800] "GET / HTTP/1.0" 304 -"-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/34.0.1847.131 Safari/537.36"

使用模式匹配

示例:

  location ~/test {  
   proxy_pass http://10.0.10.83/hello;    
    proxy_set_header X-real-ip $remote_addr;    
  }

只要客户端访问的uri中只要包含test的路径则进行跳转至于10.0.10.83的/test的物理路径;

一旦使用了模式匹配,那么后面跟上test以后里面代理的时候,后面必定不能带有路径hello,必定什么路径都不要加,它会将test的内容填充至于后面

测试:

  location ~/test {  
   proxy_pass http://10.0.10.83/hello;#必定不能带有任何字符    
    proxy_set_header X-real-ip $remote_addr;    
  }

保存退出并检查语法

[root@node1 nginx]#nginx -t

nginx:[emerg] "proxy_pass" cannot have URI part in location given byregular expression, or inside named location, or inside "if"statement, or inside "limit_except" block in /etc/nginx/nginx.conf:49

nginx:configuration file /etc/nginx/nginx.conf test failed

首先语法检测根本不经过,提示路径中不能加入uri,因此若是出现此类配置方式是连服务都不能启动的

将后面的uri去掉再测试:

       location   /test {  
          proxy_passhttp://10.0.10.83;          #注意没有斜线    
          proxy_set_headerX-real-ip $remote_addr;    
        }

总结:使用匹配模式,必定不能加uri,只是将其前端的参数传递过来

从新加载并访问测试:

[root@mode test_php]#curl http://10.0.10.61/test  
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">    
<html><head>    
<title>404 Not Found</title>

加入斜线

       location  /test {  
            proxy_passhttp://10.0.10.83/;    
            proxy_set_headerX-real-ip $remote_addr;    
        }

访问测试:

[root@modetest_php]# curl http://10.0.10.61/test  
<h1>10.0.10.83</h1>

若是location 给了uri 而proxy_pass没有跟任何uri 意味着将location的uri附加至proxy_pass 当作请求的路径,哪怕加一个斜线也表示对应的uri,因此请求的test路径相对于http://10.0.10.83/目录下的文件

基于匹配规则实现动静分离

新建location,内容以下

location  ~* \.(jpg|bng|html|css|png|gif|ico|)${  
   proxy_pass http://10.0.10.83;    
proxy_set_header X-real-ip $remote_addr;    
  }

若是访问的内容是不区分大小写的方式:

若是访问的uri后缀是以静态内容或图片格式结尾的,那么直接将请求转向10.0.10.83

检查语法并重启

[root@node1 nginx]#!ngin

[root@node1 nginx]# !ser

而后在服务10.0.10.83服务器建立目录及文件

上传某张图片或建立某路径文件并访问测试

[root@mode if]# pwd  
/var/html/php_test/if

[root@mode if]#echo "test 10.0.10.83" > 1.html

[root@mode if]#curl http://10.0.10.61/if/1.html  
1

先来测试一下访问静态内容

[root@node1 nginx]#curl http://10.0.10.61/if/1.html#指定其uri

test 10.0.10.83#能够看到,已经成功跳转至10.0.10.83

因此就算前端没有这样的路径但能映射到后端服务器相关路径都能访问的到

那么假如说有另外服务器能够访问动态内容的话,则能够将全部的动态请求直接转发至动态内容服务器

以下所示

咱们本机已经存在fastcgi,因此将nginx的fastcgi功能开启,因为9000端口在本地监听,因此这里默认便可

location ~ \.php$ {#已经默认帮咱们定义了location匹配规则,若是后缀是php的uri,那么所有转发至这个主机

root/web/htdocs;#指定其php目录

fastcgi_pass127.0.0.1:9000;#fastcgi在咱们本机已监听

fastcgi_indexindex.php;

fastcgi_paramSCRIPT_FILENAME/scripts$fastcgi_script_name;

includefastcgi_params;

}

定义在本机,

那么直接访问测试:

wKiom1NrM8vTPCdOAADCbdtRKmk245

能够发现,如今咱们将2个请求分开了

若是请求的是静态内容则到10.0.10.83上去,若是请求的是动态内容则到本机,而若是动态请求在另外服务器上部署的也彻底能够实现分割

基于匹配规则实现上传转发功能

随着咱们业务量的愈来愈大,需求将上传服务器也对其进行分离,在站点上搭建一个专门的服务器用来接收上传

有时候web服务器能够实现上传,web也支持上传,可是须要将DAV功能打开

新建虚机10.0.10.62并开启apache上传功能

[root@node2apache]# ./bin/apachectl  -M  | grep -i 'dav'  
dav_module (static)    
dav_fs_module (static)

这时只须要在DocumentRoot上对应的访问权限上启动对应的DAV便可

加入参数:

Dav on

Options Indexes FollowSymLinks

将网页目录给予写权限

[root@node2apache]# setfacl -m u:apache:rwx /var/www/html/

编辑nginx配置文件,加入if判断语句并引用$request_method模块,判断若是用户操做是put,那么将其转发至10.0.10.62

location / {

root/web/htdocs/;

indexindex.php index.html index.htm;

if ($request_method ~*"PUT"){

proxy_pass http://10.0.10.62;

break;

}

}

保存退出检查语法并从新加载配置

[root@node1 nginx]#nginx -t

nginx: theconfiguration file /etc/nginx/nginx.conf syntax is ok

nginx:configuration file /etc/nginx/nginx.conf test is successful

[root@node1 nginx]#!ser

这时咱们可使用curl -T 上传文件

[root@node1 nginx]#curl -T koi-utf http://10.0.10.62/

查看文件是否存在

[root@node2 conf]#ll /var/www/html/

total 16

-rw-r--r--. 1rootroot11 May6 18:31 index.html

-rw-r--r--. 1rootroot6 Apr 28 21:15 index.html.bak

-rw-r--r--. 1apache apache 2837 May6 00:08 koi-utf

如上,说明支持put的方法,已经能够上传

假设咱们如今代理若是用户请求的内容是上传操做则专至62这台服务器,这样就一个静态动态 一个负责上传的角色,彻底将服务角色分割开来

因而可知,咱们的服务扮演了三种角色,将上传、动态、静态内容分别分发至不一样的服务器

nginx实现负载均衡

nginx实现负载均衡有单独一模块来实现需求,叫作upstream

参考:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

示例:

#首先在全局配置中定义upstream name

upstream backend {

server backend1.example.comweight=5;

server backend2.example.com:8080;

server unix:/tmp/backend3;

server backup1.example.com:8080backup;

server backup2.example.com:8080backup;

}

#定义完成后再从location中引用

server {

location / {

proxy_pass http://backend;

}

}

一旦启动了此模块,将引入一个新的上下文(只要加大括号就表示新引入一个新的上下文)所以upstream也引入了一个新的上下文

每一个server后面跟了一个主机名或ip 能够加端口,但注意的是前面必定不能加http://

而upstream为一个关键字,后面的backend为名称,说明这是一组服务器能够被轮流访问的

以后在location定义反向代理的时候,定义的不再是某个指定服务器了而是upstream,所以用户的请求发往这个upstream之后,这个upstream模块会自动从定义的规则中每一次选择一个server 进行分发

为了演示效果,咱们将后端的apache服务器分别建立不一样的页面,步骤略

配置nginx 先将其备份,方便以后恢复

[root@node1 nginx]#cp nginx.conf nginx.conf.bak  
[root@node1 nginx]# vim nginx.conf

将以前定义的location全都删掉,步骤略

在httpd{}上下文中定义upstream

upstream webservers {

server 10.0.10.62;

server 10.0.10.83;

}

定义upstream名为webservers,其组内定义2个web主机 分别是10.0.10.62和10.0.10.83 注意的是ip前面不能加http://

定义location,以下所示

location / {

#root/web/htdocs/;

#indexindex.php index.html index.htm;

proxy_pass http://webservers;#webservers为定义的upstream的名称

}

假如用户访问的location的根目录,当访问的是根的时候直接使用proxy_pass直接映射至upstream组内的主机

保存退出检测语法并重启nginx

[root@node1 nginx]#!nginx

[root@node1 nginx]#!ser

访问以下

[root@node1 nginx]#curl http://10.0.10.61

10.0.10.62

[root@node1 nginx]#curl http://10.0.10.61

<h1>10.0.10.83</h1>

实现后端realserver健康状态检查

使其一旦出现故障再也不将其加进来

定义upstream,以下所示

upstream webservers {

#server 10.0.10.62 ;

server 10.0.10.61 max_fails=3fail_timeout=1s backup;

server 10.0.10.83 weight=1max_fails=3 fail_timeout=2s;

}

weight=1 设置其权重;

max_fails=3最大容许3次失败;

fail_timeout=2s若是超过2秒则超时;

在第三行能够看到,咱们在本机也启动一个web服务器,可是这个服务器不是专门提供工做的,一旦后端服务器出现故障,那么则转至backup服务器,使其服务器专门为用户提供错误页面

backup表示其主机始终不会生效除非组内全部主机所有故障

大功告成

相关文章
相关标签/搜索