Nginx正反向代理与负载均衡配置
By. 承祥君
系统环境:
平台:VMwear fusion For MAC
系统:CentOS release 6.5 (Final)
实验时间:2017-10-15
实验环境:
IP对应的机器名:
图示名 真正实验主机名
Client A: CCTV-1 (主机名)
Nginx Server: CCTV-2 (主机名)
Web 1: CCTV-3 (主机名)
Web 2: CCTV-4 (主机名)
实验开始:
一、正向代理
概念这里不介绍,可以参考http://my.oschina.net/yoyoko/blog/147414。
1.1 环境介绍
1.2 配置介绍
[root@CCTV-2 ~]# cat /usr/local/nginx/nginx.conf
1 server { 2 listen 80; 3 server_name 172.16.1.20; 4 #charset koi8-r; 5 #access_log logs/host.access.log main; 6 resolver 114.114.114.114 #这里是DNS,访问外网 7 location / { 8 proxy_pass http://$http_host$request_uri; # $http_host和$request_uri是nginx系统变量,不需要替换,保持原样 10 # root html; 11 # index index.html index.htm; 12 }
Nginx client:
只有一个内网网卡,通过访问Nginx server去访问internet,其实FQ、肉鸡、之类的俗称就是这个原理。
[root@CCTV-1 ~]# wget http://www.baidu.com --2017-10-16 03:14:27-- http://www.baidu.com/ Resolving www.baidu.com... failed: Name or service not known. wget: unable to resolve host address ‚Äúwww.baidu.com‚Äù [root@CCTV-1 ~]# export http_proxy=http://172.16.1.20:80 [root@CCTV-1 ~]# wget www.baidu.com #可以成功访问百度了 --2017-10-16 03:14:35-- http://www.baidu.com/ 正在连接 10.0.0.136:80... 已连接。 已发出 Proxy 请求,正在等待回应... 200 OK 长度:未指定 [text/html] 正在保存至: “index.html.1” [ <=> ] 99,762 --.-K/s in 0.07s 2017-10-16 03:14:37 (1.36 MB/s) - “index.html.1” 已保存 [99762]
二、反向代理
2.1 环境介绍
2.2 配置介绍
[root@CCTV-2 conf.d]# cat nginx.conf server { listen 80; server_name 172.16.1.20; #根据环境介绍,nginx server ip location / { proxy_pass http://192.168.8.30; #被代理的服务器ip } #proxy_pass: proxy_pass URL #默认值:NO #使用字段:location,location中的if字段 #这个参数设置被代理服务器的地址和被映射的URL,地址可以使主机名、域名、IP加端口的模式,如: #proxy_pass http://192.168.8.30:8099/second/; [root@CCTV-2 conf.d]# ./usr/local/nginx/nginx -s reload #重启加载配置
看下结果:#先登录到实验环境中的clinet机上,ip如下:
[root@CCTV-1 ~]# ifconfig eth0 Link encap:Ethernet HWaddr 08:00:27:3D:40:40 inet addr:172.16.1.10 Bcast:10.255.255.255 Mask:255.0.0.0 inet6 addr: fe80::a00:27ff:fe3d:4040/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2618345 errors:0 dropped:0 overruns:0 frame:0 TX packets:247926 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:336182790 (320.6 MiB) TX bytes:35145157 (33.5 MiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:177352 errors:0 dropped:0 overruns:0 frame:0 TX packets:177352 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:26547640 (25.3 MiB) TX bytes:26547640 (25.3 MiB) [root@CCTV-1 ~]# curl 172.16.1.20 #访问反向代理服务器 <html> welcome to 192.168.8.30!! </html> #我们看到访问代理服务器,结果被转发到了Web 1上。 #接下来我们分别看下nginx-server和Web 1的日志:
nginx-server:
[root@CCTV-2~]# tail /usr/local/nginx/logs/access.log
172.16.1.10 - - [16/Oct/2017:02:25:57 +0800] "GET / HTTP/1.1" 200 46 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
web-server:
[root@CCTV-3 ~]# tail -f /var/log/httpd/access_log
172.16.1.10</span> - - [16/Oct/2017:02:25:30 +0800] "GET / HTTP/1.0" 200 46 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
##我们看到nginx-server上的nginx的日志,显示访问的用户是我们环境的clinet, #而web-1上显示的ip是是nginx-server。 #说白了反向代理,对客户来说nginx-server就是真正的服务器,实际上,当用户访问nginx-server的时候,会将请求转发到 #web-1上,然后web-1将请求的结果发给nginx-server,然后由nginx-server将请求的结果转交给用户。 #在web-server上看到的都是代理的ip,能不能也看到真实用户的ip呢? [root@CCTV-2 conf.d]# cat nginx.conf server { listen 80; server_name 172.16.1.20; #根据环境介绍,nginx server ip location / { proxy_pass http://192.168.8.30; #被代理的服务器ip proxy_set_header X-Real-IP $remote_addr; #多了这行 }
[root@CCTV-2 ]# ./nginx -s reload [root@CCTV-3 ~]# tail /var/log/httpd/access_log 192.168.8.20 - - [15/Oct/2017:16:10:53 +0800] "GET / HTTP/1.0" 200 26 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" #改了之后还是显示的是代理服务器的ip,我们去web-server上修改下配置 [root@CCTV-3 ~]# vim /etc/httpd/conf/httpd.conf LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent #修改为:(%h指的的访问的主机,现在改为访问的真实主机ip) LogFormat "%{X-Real-IP}i</span> %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent</span>
[root@CCTV-3 ~]# service httpd restart 停止 httpd: [确定] 正在启动 httpd: [确定] [root@CCTV-3 ~]# tail /var/log/httpd/access_log 172.16.1.10 - - [15/Oct/2017:16:10:53 +0800] "GET / HTTP/1.0" 200 26 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" <span style="color:#FF0000;">10.0.0.139</span> - - [08/Jun/2016:16:16:01 +0800] "GET / HTTP/1.0" 200 26 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" #已经变成了真实的访问地址
2.3 代理多个WEB服务器:
[root@CCTV-2 conf.d]# cat nginx.conf server { listen 80; server_name 172.16.1.20; location / { proxy_pass http://192.168.1.30; proxy_set_header X-Real-IP $remote_addr; } location /web2 { #多加个location proxy_pass http://192.168.1.40/; #注意末尾多了一个"/",详细请参考我另一篇文章“Nginx的4种配置” proxy_set_header X-Real-IP $remote_addr; } #我们去client上访问试试: [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> #访问成功 [root@clint ~]# curl 172.16.1.20/web2 <html> 192.168.8.40 </html> #访问成功
三、负载均衡
负载均衡实现的方式有很多,常用的lvs四层负载均衡,nginx是七层负载均衡,可以网上查询相关资料。
3.1 环境介绍
3.2 配置介绍
1.upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。在上面的设定中,通过upstream指令指定了一个负载均衡器的名称1.2.3.4。这个名称可以任意指定,在后面需要用到的地方直接调用即可。
2.Nginx的负载均衡模块目前支持4种调度算法,下面进行分别介绍,其中后两项属于第三方调度算法。
-
轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
-
ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
-
fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
-
url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。
3.upstream 支持的状态参数
在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。
我们来看下具体配置:
[root@CCTV-2 ]# cat nginx.conf http { include /etc/nginx/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 /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; upstream HZ.COM { server 192.168.8.30:80; server 192.168.8.40:80; } include /etc/nginx/conf.d/*.conf; } location / { proxy_pass http://HZ.COM; proxy_set_header X-Real-IP $remote_addr; } #注,upstream是定义在server{ }之外的,不能定义在server{ }内部。定义好upstream之后,用proxy_pass引用一下即可。
4.测试结果
[root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.40 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> #结果是Web1,2交替出现,说明默认是轮询方式的负载均衡。
5.健康检查
一般健康检查都需要搞个keepalived,但nginx也有相应的参数可以设置。
-
max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
-
fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行健康状态检查。
6.测试下结果
[root@CCTV-3 httpd]# service httpd stop #关闭web-server1服务 [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.40 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.40 </html> #现在只能访问web-server2了。 [root@CCTV-3 httpd]# service httpd start #打开web-server1服务 [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.40 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html>
7.ip_hash的负载均衡
[root@CCTV-2 ]# cat nginx.conf upstream HZ.COM { ip_hash; server 192.168.8.30:80 weight=1 max_fails=2 fail_timeout=2; server 192.168.8.40:80 weight=1 max_fails=2 fail_timeout=2; } [root@CCTV-2 ]# ]# ./nginx -s reload [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> [root@CCTV-1 ~]# curl 172.16.1.20 <html> 192.168.8.30 </html> #配置这种负载均衡后,>每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器, #有效解决了动态网页存在的session共享问题。(一般电子商务网站用的比较多)