内容:

1、何为代理

2、nginx的反向代理模块以及使用

3、nginx的负载均衡模块以及使用


一、何为代理

代理,由字面意思可以理解为代为服务的是意思。

代理服务技术是一门很古老的技术,是在互联网早期出现就使用的技术。一般实现代理技术的方式就是在服务器上安装代理服务软件,让其成为一个代理服务器,从而实现代理技术。常用的代理技术分为正向代理、反向代理。

正向代理:

正常的用户访问站点是客户打开浏览器,然后输入相关的网站进行浏览,其实这就是一个代理的行为,只不过代理的是浏览器,我们通过浏览器来代理请求站点服务,而正向代理服务器可以理解为:

 nginx的反向代理以及负载均衡模块的使用_第1张图片

反向代理:反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。 

nginx的反向代理以及负载均衡模块的使用_第2张图片

所以,nginx由于起轻量高效的特性,是的其成为了反向代理服务器的热门选择。

二、ngixn的反向代理模块以及使用

ngx_http_proxy_module模块:

1、proxy_pass URL;

Context: location, if in location, limit_except

(1)注意:proxy_pass后面的路径不带uri时,其会将location的uri传递给后端主机;

server {

...

server_name HOSTNAME;

location /uri/ {

proxy http://hos[:port];

}

...

}

效果:http://HOSTNAME/uri --> http://host/uri

 

(2)proxy_pass后面的路径是一个uri时,其会将location的uri替换为proxy_pass的uri;

server {

...

server_name HOSTNAME;

location /uri/ {

proxy http://host/new_uri/;

}

...

}

效果:http://HOSTNAME/uri/ --> http://host/new_uri/

(3)如果location定义其uri时使用了正则表达式的模式,则proxy_pass之后必须不能使用uri; 用户请求时传递的uri将直接附加代理到的服务的之后;

server {

...

server_name HOSTNAME;

location ~|~* /uri/ {

proxy http://host;

}

...

}

效果:http://HOSTNAME/uri/ --> http://host/uri/;

2、proxy_set_header field value;设定发往后端主机的请求报文的请求首部的值;Context: http, server, location,常用于标记客户端的真是IP地址

例:

proxy_set_header X-Real-IP  $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

3、proxy_cache_path:定义可用于proxy功能的缓存;Context: http

proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_

4、proxy_cache zone | off;

指明要调用的缓存,或关闭缓存机制;Context: http, server, location

5、 proxy_cache_key string;

缓存中用于“键”的内容;

默认值:proxy_cache_key $scheme$proxy_host$request_uri;

6、proxy_cache_valid [code ...] time;

定义对特定响应码的响应内容的缓存时长;

定义在http{...}中;

proxy_cache_path /var/cache/nginx/proxy_cache levels=1:1:1 keys_zone=pxycache:20m max_size=1g;

定义在需要调用缓存功能的配置段,例如server{...};

proxy_cache pxycache;

proxy_cache_key $request_uri;

proxy_cache_valid 200 302 301 1h;

proxy_cache_valid any 1m;

7、proxy_cache_use_stale

proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ...;

Determines in which cases a stale cached response can be used when an error occurs during communication with the proxied server.

8、proxy_cache_methods GET | HEAD | POST ...;

只有标记的相关请求方法才进行缓存

9、proxy_hide_header field;

By default, nginx does not pass the header fields “Date”, “Server”, “X-Pad”, and “X-Accel-...” from the response of a proxied server to a client. The proxy_hide_header directive sets additional fields that will not be passed.

10、proxy_connect_timeout time;

Defines a timeout for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds.

默认为60s;

ngx_http_headers_module模块  

    向由代理服务器响应给客户端的响应报文添加自定义首部,或修改指定首部的值;  

    1、add_header name value [always];

    添加自定义首部;

  例:

    add_header X-Via  $server_addr;

    add_header X-Accel $server_name;

   

    2、expires [modified] time;

    expires epoch | max | off;

    用于定义Expire或Cache-Control首部的值;

下面来进行操作效果的演示:

规划:nginx反代的服务IP:10.1.249.75,后端真实服务器IP:10.1.252.235

在ngixn服务器中配置:

修改ngixn的反向代理服务中的配置文件,启动反向代理模式

   location / {
        #root   /usr/share/nginx/html;
        proxy_pass http://10.1.252.235;
        index  index.html index.htm;
    }
[root@localhost upload]# ifconfig
eno16777736: flags=4163  mtu 1500
        inet 10.1.249.75  netmask 255.255.0.0  broadcast 10.1.255.255
        inet6 fe80::20c:29ff:fe65:55a6  prefixlen 64  scopeid 0x20
        ether 00:0c:29:65:55:a6  txqueuelen 1000  (Ethernet)
        RX packets 9647  bytes 1463932 (1.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1736  bytes 231308 (225.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


在真实服务器中提供测试页面:

[root@localhost html]# cat index.html 
RS1


在客户端测试,已经成功访问只后端服务器

[root@localhost ~]# curl 10.1.249.75
RS1
[root@localhost ~]# curl 10.1.249.75
RS1


查看真实服务器的访问日志,发现访问的客户段IP是代理服务器的IP:

[root@localhost html]# tail /var/log/httpd/access_log 
10.1.249.75 - - [28/Oct/2016:20:10:46 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:46 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:46 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:49 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"


有没有办法获取真正的客户端IP呢?答案是肯定的,nginx提供了自身的变量可以提取原始客户的请求报文信息,只需要保留原客户端的真实IP即可

修改nginx的配置文件,添加其中一条命令:proxy_set_header X-Real-IP $remote_addr;

   

location / {
        #root   /usr/share/nginx/html;
        proxy_pass http://10.1.252.235;
        proxy_set_header X-Real-IP $remote_addr;
        index  index.html index.htm;
    }
[root@localhost upload]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost upload]# nginx -s reload

            再次测试,并访问日志:

[root@localhost html]# tail /var/log/httpd/access_log 
10.1.249.75 - - [28/Oct/2016:20:10:46 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:49 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:16:01 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:16:04 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"


发现源IP还是没有变,这是因为httpd的配置文件定义了日志的格式,只需要简单修改日志格式即可,讲%h改为之前nginx定义的报文首部{X-Real-IP}i

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


再次测试,并访问日志,已经能正确记录远端客户的IP了!

[root@localhost html]# !tai
tail /var/log/httpd/access_log 
10.1.249.75 - - [28/Oct/2016:20:10:47 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:48 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:10:49 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:16:01 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.249.75 - - [28/Oct/2016:20:16:04 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.252.215 - - [28/Oct/2016:20:19:40 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.252.215 - - [28/Oct/2016:20:19:40 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
10.1.252.215 - - [28/Oct/2016:20:19:41 +0800] "GET / HTTP/1.0" 200 4 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"


三、nginx的负载均衡模块以及使用

与lvs不同的是,nginx在应用层提供了强大的负载均衡的功能,并带有后端服务的健康检查功能。

nginx的负载均衡模块怎么使用?

ngx_http_upstream_module模块 (定义在http上下文)

1、upstream name { ... }

定义后端服务器组,会引入一个新的上下文;Context: http

upstream httpdsrvs {

server ...

server...

...

}

2、server address [parameters];

在upstream上下文中server成员,以及相关的参数;Context: upstream

address的表示格式:

unix:/PATH/TO/SOME_SOCK_FILE

IP[:PORT]

HOSTNAME[:PORT]

parameters:

weight=number

权重,默认为1;

max_fails=number

失败尝试最大次数;超出此处指定的次数时,server将被标记为不可用;

fail_timeout=time

设置将服务器标记为不可用状态的超时时长;

max_conns

当前的服务器的最大并发连接数;

backup

将服务器标记为“备用”,即所有服务器均不可用时此服务器才启用;

down

标记为“不可用”;

3、least_conn;

最少连接调度算法,当server拥有不同的权重时其为wlc;

4、 ip_hash;

源地址hash调度方法;

5、hash key [consistent];

基于指定的key的hash表来实现对请求的调度,此处的key可以直接文本、变量或二者的组合;

作用:将请求分类,同一类请求将发往同一个upstream server;

示例:

hash $request_uri consistent;

hash $remote_addr;

6、keepalive connections;

为每个worker进程保留的空闲的长连接数量;

下面来实验验证:

规划:nginx反代的服务IP:10.1.249.75,后端服务器RS1:10.1.252.235,后端服务器RS2:10.1.252.215

(1)RS1,RS2启动web服务,并提供相关的测试页面

(2)配置nginx的负载均衡:

在httpd段添加:

   

upstream test {
    server 10.1.252.235;
    server 10.1.252.215;
}

(3)启动反向代理模式,并实现负载均衡:

   

location / {
        #root   /usr/share/nginx/html;
        proxy_pass http://test;
        proxy_set_header X-Real-IP $remote_addr;
        index  index.html index.htm;
    }
[root@localhost upload]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost upload]# nginx -s reload

(4)客户端测试,已经可以实现负载均衡功能(默认是轮询rr算法):

[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2


(5)添加权重测试:

 

  upstream test {
    server 10.1.252.235 weight=2;
    server 10.1.252.215;
}
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS2
[root@localhost ~]# curl http://10.1.249.75
RS1
[root@localhost ~]# curl http://10.1.249.75
RS1

(6)我们知道,lvs的负载均衡调度中,lvs自身并没有对后端服务器进行健康状态检测的机制,也就是说后端服务器挂了还是会照样进行调度,而ngixn则进行健康状态检查。修改配置如下:

 

  upstream test {
    server 10.1.252.235 max_fails=3 fail_timeout=10;
    server 10.1.252.215 max_fails=3 fail_timeout=10;
}

        (7)停掉RS1前的测试:

[root@localhost ~]# for i in `seq 10`;do curl http://10.1.249.75;done 
RS1
RS2
RS1
RS2
RS1
RS2
RS1
RS2
RS1
RS2

        (8)停掉RS1测试:

[root@localhost html]# service httpd stop
Stopping httpd:                                            [  OK  ]
[root@localhost html]# 
[root@localhost ~]# for i in `seq 10`;do curl http://10.1.249.75;done 
RS2
RS2
RS2
RS2
RS2
RS2
RS2
RS2
RS2
RS2

(9)已经自动把RS排除,现在再次恢复RS测试:

[root@localhost ~]# for i in `seq 10`;do curl http://10.1.249.75;done 
RS2
RS1
RS2
RS1
RS2
RS1
RS2
RS1
RS2
RS1


        好了nginx的反向代理和负载均衡功能就演示到这里,更多文章请关注 我的博客