大纲

一、前言

二、环境准备

三、安装与配置Nginx

四、Nginx之反向代理

五、Nginx之负载均衡

六、Nginx之页面缓存

七、Nginx之URL重写

八、Nginx之读写分离

注,操作系统为 CentOS 6.4 x86_64 , Nginx 是版本是最新版的1.4.2,所以实验用到的软件请点击这里下载:http://yunpan.cn/QXIgqMmVmuZrm

一、前言

       在前面的几篇博文中我们主要讲解了Nginx作为Web服务器知识点,主要的知识点有nginx的理论详解、nginx作为web服务器的操作讲解、nginx作为LNMP架构的讲解,不清楚的博友可以回头看看,在这一篇博客中我们主要讲解, nginx的反向代理、负载均衡、缓存、URL重写以及读写分离详解。好了,下面我们来具体说一说。

二、环境准备

1. 操作系统

  • CentOS 6.4 x86_64

2.软件版本

  • Nginx 1.4.2

3.实验拓扑

注,实验拓扑见下文。

4.安装yum源

1
2
3
[root@nginx ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@web1 ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@web2 ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

5.各节点时间同步

1
2
3
[root@nginx ~] # ntpdate 202.120.2.101
[root@web1 ~] # ntpdate 202.120.2.101
[root@web2 ~] # ntpdate 202.120.2.101

6.关闭防火墙与SELinux

1
2
3
4
5
6
7
8
9
10
11
12
[root@nginx ~] # service iptables stop
[root@nginx ~] # chkconfig iptables off 
[root@nginx ~] # getenforce 
Disabled
[root@web1 ~] # service iptables stop
[root@web1 ~] # chkconfig iptables off 
[root@web1 ~] # getenforce 
Disabled
[root@web2 ~] # service iptables stop
[root@web2 ~] # chkconfig iptables off 
[root@web2 ~] # getenforce 
Disabled

三、安装Nginx

1.解压

1
[root@nginx src] # tar xf nginx-1.4.2.tar.gz

2.新建nginx用户与组

1
2
3
4
[root@nginx src] # groupadd -g 108  -r nginx
[root@nginx src] # useradd -u 108 -r -g 108 nginx 
[root@nginx src] # id nginx 
uid=108(nginx) gid=108(nginx) 组=108(nginx)

3.准备编译配置文件

1
2
[root@nginx src] # yum install -y pcre-devel openssl-devel
[root@nginx nginx-1.4.2] # ./configure   --prefix=/usr   --sbin-path=/usr/sbin/nginx   --conf-path=/etc/nginx/nginx.conf   --error-log-path=/var/log/nginx/error.log   --http-log-path=/var/log/nginx/access.log   --pid-path=/var/run/nginx/nginx.pid    --lock-path=/var/lock/nginx.lock   --user=nginx   --group=nginx   --with-http_ssl_module   --with-http_flv_module   --with-http_stub_status_module   --with-http_gzip_static_module   --http-client-body-temp-path=/var/tmp/nginx/client/   --http-proxy-temp-path=/var/tmp/nginx/proxy/   --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/   --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi   --http-scgi-temp-path=/var/tmp/nginx/scgi   --with-pcre

4.编译并安装

1
[root@nginx nginx-1.4.2] # make && make install

5.为nginx提供SysV init脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
[root@nginx ~] # cat /etc/init.d/nginx
#!/bin/sh 
# nginx - this script starts and stops the nginx daemon 
# chkconfig:   - 85 15 
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \ 
#               proxy and IMAP/POP3 proxy server 
# processname: nginx 
# config:      /etc/nginx/nginx.conf 
# config:      /etc/sysconfig/nginx 
# pidfile:     /var/run/nginx.pid 
# Source function library. 
. /etc/rc.d/init.d/functions 
# Source networking configuration. 
. /etc/sysconfig/network 
# Check that networking is up. 
"$NETWORKING"  "no"  ] && exit 0 
nginx= "/usr/sbin/nginx" 
prog=$(basename $nginx) 
NGINX_CONF_FILE= "/etc/nginx/nginx.conf" 
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx 
lockfile=/ var /lock/subsys/nginx 
make_dirs() { 
    # make required directories 
    user=`nginx -V 2>&1 | grep  "configure arguments:"  | sed  's/[^*]*--user=\([^ ]*\).*/\1/g'  -` 
    options=`$nginx -V 2>&1 | grep  'configure arguments:'
    for  opt  in  $options;  do 
        if  [ `echo $opt | grep  '.*-temp-path' ` ]; then 
            value=`echo $opt | cut -d  "="  -f 2` 
            if  [ ! -d  "$value"  ]; then 
                # echo "creating" $value 
                mkdir -p $value && chown -R $user $value 
            fi 
        fi 
    done 
start() { 
     [ -x $nginx ] || exit 5 
     [ -f $NGINX_CONF_FILE ] || exit 6 
     make_dirs 
     echo -n $ "Starting $prog: " 
     daemon $nginx -c $NGINX_CONF_FILE 
     retval=$? 
     echo 
     [ $retval -eq 0 ] && touch $lockfile 
     return  $retval 
stop() { 
     echo -n $ "Stopping $prog: " 
     killproc $prog -QUIT 
     retval=$? 
     echo 
     [ $retval -eq 0 ] && rm -f $lockfile 
     return  $retval 
restart() { 
     configtest ||  return  $? 
     stop 
     sleep 1 
     start 
reload() { 
     configtest ||  return  $? 
     echo -n $ "Reloading $prog: " 
     killproc $nginx -HUP 
     RETVAL=$? 
     echo 
force_reload() { 
     restart 
configtest() { 
   $nginx -t -c $NGINX_CONF_FILE 
rh_status() { 
     status $prog 
rh_status_q() { 
     rh_status >/dev/ null  2>&1 
case  "$1"  in 
     start) 
         rh_status_q && exit 0 
         $1 
         ;; 
     stop) 
         rh_status_q || exit 0 
         $1 
         ;; 
     restart|configtest) 
         $1 
         ;; 
     reload) 
         rh_status_q || exit 7 
         $1 
         ;; 
     force-reload) 
         force_reload 
         ;; 
     status) 
         rh_status 
         ;; 
     condrestart| try -restart) 
         rh_status_q || exit 0 
             ;; 
     *) 
         echo $ "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" 
         exit 2 
esac

6.为此脚本赋予执行权限

1
[root@nginx ~] # chmod +x /etc/init.d/nginx

7.添加至服务管理列表,并让其开机自动启动

1
2
3
4
[root@nginx ~] # chkconfig --add nginx
[root@nginx ~] # chkconfig nginx on 
[root@nginx ~] # chkconfig nginx --list 
nginx              0:关闭    1:关闭    2:启用    3:启用    4:启用    5:启用    6:关闭

8.启动nginx

1
2
[root@nginx ~] # service nginx start
正在启动 nginx:                                           [确定]

9.查看一下端口

1
2
[root@nginx ~] # netstat -ntlp | grep :80
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      3889/nginx

10.测试一下2033581_1378277128W8iY.png

好了,Nginx安装与配置就到这里,下面我们来说一说Nginx的反向代理。

四、Nginx之反向代理

在配置nginx反向代理之间我们得先准备两台测试服务器,Web1与Web2。

1.安装httpd

1
2
[root@web1 ~] # yum install -y httpd
[root@web2 ~] # yum install -y httpd

2.提供测试页面

1
2
[root@web1 ~] # echo "<h1>web1.test.com</h1>" > /var/www/html/index.html
[root@web2 ~] # echo "<h1>web2.test.com</h1>" > /var/www/html/index.html

3.启动httpd服务

1
2
3
4
[root@web1 ~] # service httpd start
正在启动 httpd:                                           [确定]
[root@web2 ~] # service httpd start
正在启动 httpd:                                           [确定]

4.测试一下

t2

t3

5.简单说一下,正向代理与反向代理

(1).正向代理的概念

       正向代理,也就是传说中的代理,他的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

       结论就是,正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

(2).反向代理的概念

继续举例:    
       例用户访问 
http://www.test.com/readme,但www.test.com上并不存在readme页面,他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能。

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

(3).两者区别

用途上来讲:

       正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。反向代理的典型用途是将防火墙后面的服务器提供给Internet用户访问。反向代理还可以为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。另外,反向代理还可以启用高级URL策略和管理技术,从而使处于不同web服务器系统的web页面同时存在于同一个URL空间下。

安全性来讲:

       正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此你必须采取安全措施以确保仅为经过授权的客户端提供服务。反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。

6.nginx 代理模块

http 代理官方中文文档http://www.howtocn.org/nginx:nginx%E6%A8%A1%E5%9D%97%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88:standardhttpmodules:httpproxy

说明:代理模块的指令有很多我这里只讲解重要的proxy_pass,想了解更多代理指令请参考官方中文文档。

这个模块可以转发请求到其他的服务器。HTTP/1.0无法使用keepalive(后端服务器将为每个请求创建并且删除连接)。nginx为浏览器发送HTTP/1.1并为后端服务器发送HTTP/1.0,这样浏览器就可以为浏览器处理keepalive。     
如下例:

1
2
3
4
location / {
   proxy_pass        http: //localhost:8000;
   proxy_set_header  X-Real-IP  $remote_addr;
}

注意,当使用http proxy模块(甚至FastCGI),所有的连接请求在发送到后端服务器之前nginx将缓存它们,因此,在测量从后端传送的数据时,它的进度显示可能不正确。

实验拓扑:

nginx4

7.配置http反向代理

1
2
3
4
5
6
[root@nginx ~] # cd /etc/nginx/
[root@nginx nginx] # cp nginx.conf nginx.conf.bak #备份一个原配置文件
[root@nginx nginx] # vim nginx.conf
location / {
                proxy_pass      http: //192.168.18.201;
        }

语法:proxy_pass URL指令说明:proxy_pass

默认值:no       
使用字段:location, location中的if字段       
这个指令设置被代理服务器的地址和被映射的URI,地址可以使用主机名或IP加端口号的形式,例如:
proxy_pass http://localhost:8000/uri/;

8.重新加载一下配置文件

1
2
3
4
[root@nginx ~] # service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新载入 nginx:                                           [确定]

9.测试一下

t4

注,大家可以看到,当我们访问192.168.18.208时,被代理重新定向到Web1上。

10.查看一下Web服务器日志

1
2
3
4
5
6
7
8
9
10
11
[root@web1 ~] # tail /var/log/httpd/access_log
192.168.18.208 - - [04/Sep/2013:00:14:20 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:14:20 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:14:20 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.138 - - [04/Sep/2013:00:14:45 +0800]  "GET / HTTP/1.1"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.138 - - [04/Sep/2013:00:14:48 +0800]  "GET /favicon.ico HTTP/1.1"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:14:55 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:15:05 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:15:13 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:15:16 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04/Sep/2013:00:15:16 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

注,大家可以看到我们这里的客户的IP全是,nginx代理服务器的IP,并不是真实客户端的IP。下面我们修改一下,让日志的IP显示真实的客户端的IP。

11.修改nginx配置文件

1
2
3
4
location / {
         proxy_pass      http: //192.168.18.201;
         proxy_set_header  X-Real-IP  $remote_addr;  #加上这一行
}

指令说明proxy_set_header

语法:proxy_set_header header value 
默认值: Host and Connection 
使用字段:http, server, location 
这个指令允许将发送到被代理服务器的请求头重新定义或者增加一些字段。这个值可以是一个文本,变量或者它们的组合。proxy_set_header在指定的字段中没有定义时会从它的上级字段继承。

12.重新加载一下配置文件

1
2
3
4
[root@nginx ~] # service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新载入 nginx:                                           [确定]

13.测试并查看日志

1
2
3
4
5
6
7
8
9
10
11
[root@web1 ~] # tail /var/log/httpd/access_log
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03/Sep/2013:16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到日志记录的还是代理的IP,没有显示真实客户端的IP,为什么呢?我们来看一下httpd的配置文件。

14.查看并修改httpd配置文件

[root@web1 ~]# vim /etc/httpd/conf/httpd.conf

t5

注,大家可以这里记录日志的参数还是%h,下面我们修改一下参数。

t6

注,这是修改后的参数,将h%修改为%{X-Real-IP}i,好的下面我们再来测试一下。

15.重启并测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@web1 ~] # service httpd restart
停止 httpd:                                               [确定]
正在启动 httpd:                                           [确定]
[root@web1 ~] # tail /var/log/httpd/access_log
192.168.18.138 - - [03/Sep/2013:17:09:14 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:14 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03/Sep/2013:17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到现在的日志里记录的IP地址就是真实的客户端地址了。好了,到这里Nginx代理后端一台服务器就演示到这里,下面我们继续说。

五、Nginx之负载均衡

注,大家可以看到,由于我们网站是发展初期,nginx只代理了后端一台服务器,但由于我们网站名气大涨访问的人越来越多一台服务器实在是顶不住,于是我们加了多台服务器,那么多台服务器又怎么配置代理呢,我们这里以两台服务器为案例,为大家做演示。

1.upstream 负载均衡模块说明

案例:

下面设定负载均衡的服务器列表。

1
2
3
4
5
6
7
8
9
10
11
12
upstream test.net{
ip_hash;
server 192.168.10.13:80;
server 192.168.10.14:80  down;