大纲

一、环境准备

二、编译安装Nginx

三、Nginx反向代理

四、Nginx负载均衡

五、Nginx缓存功能

六、Nginx之URL重写

七、Nginx读写分离






一、环境准备

系统环境

CentOS5.8 x86_64

172.16.1.101        nginx

172.16.1.102        web1

172.16.1.103        web2

软件包

nginx-1.8.0.tar.gz


1、时间同步

[root@nginx ~]# ntpdate s2c.time.edu.cn
20 Jan 10:20:44 ntpdate[31442]: adjust time server 202.112.10.36 offset -0.014753 sec

[root@web1 ~]# ntpdate s2c.time.edu.cn
20 Jan 10:12:53 ntpdate[31373]: adjust time server 202.112.10.36 offset -0.007873 sec

[root@web2 ~]# ntpdate s2c.time.edu.cn
20 Jan 10:12:46 ntpdate[4132]: step time server 202.112.10.36 offset 1432097.703563 sec

2、关闭iptables和selinux

nginx
[root@nginx ~]# service iptables stop
[root@nginx ~]# chkconfig iptables off
[root@nginx ~]# sed -r -i  "s/^(SELINUX=).*/\1permissive/g" /etc/sysconfig/selinux
[root@nginx ~]# setenforce 0
[root@nginx ~]# getenforce 
Permissive

web1
[root@web1 ~]# service iptables stop
[root@web1 ~]# chkconfig iptables off
[root@web1 ~]# sed -r -i  "s/^(SELINUX=).*/\1permissive/g" /etc/sysconfig/selinux
[root@web1 ~]# setenforce 0
[root@web1 ~]# getenforce 
Permissive

web2
[root@web2 ~]# service iptables stop
[root@web2 ~]# chkconfig iptables off
[root@web2 ~]# sed -r -i  "s/^(SELINUX=).*/\1permissive/g" /etc/sysconfig/selinux
[root@web2 ~]# setenforce 0
[root@web2 ~]# getenforce 
Permissive

3、下载所需的软件包

nginx
[root@nginx ~]# wget http://nginx.org/download/nginx-1.8.0.tar.gz


二、编译安装Nginx

1、解决依赖关系

[root@nginx ~]# yum groupinstall -y "Development Tools" "Development Libraries"
[root@nginx ~]# yum install openssl-devel pcre-devel

2、创建nginx用户和组

[root@nginx ~]# groupadd -r nginx 
[root@nginx ~]# useradd -r -g nginx nginx

3、编译安装

[root@nginx ~]# tar xf nginx-1.8.0.tar.gz 
[root@nginx ~]# cd nginx-1.8.0
[root@nginx nginx-1.8.0]# ls
auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  Makefile  man  objs  README  src

[root@nginx nginx-1.8.0]# ./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

显示我们自定义的配置信息和编译选项
Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + md5: using OpenSSL library
  + sha1: using OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr"
  nginx binary file: "/usr/sbin/nginx"
  nginx configuration prefix: "/etc/nginx"
  nginx configuration file: "/etc/nginx/nginx.conf"
  nginx pid file: "/var/run/nginx/nginx.pid"
  nginx error log file: "/var/log/nginx/error.log"
  nginx http access log file: "/var/log/nginx/access.log"
  nginx http client request body temporary files: "/var/tmp/nginx/client/"
  nginx http proxy temporary files: "/var/tmp/nginx/proxy/"
  nginx http fastcgi temporary files: "/var/tmp/nginx/fcgi/"
  nginx http uwsgi temporary files: "/var/tmp/nginx/uwsgi"
  nginx http scgi temporary files: "/var/tmp/nginx/scgi"

编译安装
[root@nginx nginx-1.8.0]# make && make install

补充:
Nginx可以使用Tmalloc(快速、多线程的malloc库及优秀性能分析工具)来加速内存分配
使用此功能需要事先安装gperftools,而后在编译nginx添加--with-google_perftools_module选项即可

4、为nginx提供SysV init脚本

[root@nginx nginx-1.8.0]# vim /etc/rc.d/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

添加执行权限,并加入到服务列表中
[root@nginx nginx-1.8.0]# chmod +x /etc/rc.d/init.d/nginx
[root@nginx nginx-1.8.0]# chkconfig --add nginx
[root@nginx nginx-1.8.0]# chkconfig nginx on
[root@nginx nginx-1.8.0]# chkconfig --list nginx
nginx          	0:off	1:off	2:on	3:on	4:on	5:on	6:off

5、启动Nginx服务

[root@nginx nginx-1.8.0]# service nginx start
Starting nginx:                                            [  OK  ]

查看80端口是否处于监听状态
[root@nginx nginx-1.8.0]# netstat -tnlp 
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address      Foreign Address    State       PID/Program name   
tcp        0      0 0.0.0.0:111        0.0.0.0:*          LISTEN      2820/portmap        
tcp        0      0 0.0.0.0:80         0.0.0.0:*          LISTEN      30414/nginx         
tcp        0      0 0.0.0.0:22         0.0.0.0:*          LISTEN      25126/sshd          
tcp        0      0 0.0.0.0:922        0.0.0.0:*          LISTEN      2860/rpc.statd      
tcp        0      0 127.0.0.1:6011     0.0.0.0:*          LISTEN      24814/sshd          
tcp        0      0 :::22              :::*               LISTEN      25126/sshd          
tcp        0      0 ::1:6011           :::*               LISTEN      24814/sshd

6、测试访问

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux

三、Nginx反向代理

1、首先准备一个web服务器,这里以web1演示

首先安装web服务,这里使用yum安装httpd,以httpd作为web服务器
[root@web1 ~]# yum install -y httpd

2、配置并启动httpd服务,测试能正常访问

创建目录,配置页面文件
[root@web1 ~]# mkdir /var/www/html/bbs
[root@web1 ~]# echo "<h1>Forum On Apache Server</h1>" > var/www/html/bbs/index.html 

启动httpd服务
[root@web1 ~]# service httpd start
Starting httpd:                                            [  OK  ]

测试自己能否访问,当前web1的ip地址就是172.16.1.102
[root@web1 ~]# curl http://172.16.1.102/bbs/
<h1>Forum On Apache Server</h1>

3、配置Nginx作为反向代理

这是切换到nginx主机,配置其作为反向代理服务器
[root@nginx ~]# hostname 
nginx

编辑配置文件,加入下面三行至server段中
[root@nginx ~]# vim /etc/nginx/nginx.conf
location /forum {
     proxy_pass http://172.16.1.102/bbs;
}

4、用浏览器测试访问

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_02

再来看web1上的访问日志
[root@web1 ~]# tail /var/log/httpd/access_log
172.16.1.101 - - [20/Jan/2016:13:57:21 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"

可以看到源ip是nginx反向代理并不是我们真正的客户端,但是有时候我们需要记录真正的client便于做日志分析
此时我们只需要添加proxy模块的proxy_set_header指令即可实现,此指令的语法格式如下

Syntax:	proxy_set_header field value;
Default:	
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context:	http, server, location

5、配置Nginx反向代理和web服务器,使web服务器能够记录真实客户端ip地址

编辑配置文件,修改反向代理location那一段如下
[root@nginx ~]# vim /etc/nginx/nginx.conf
location /forum {
       proxy_pass http://172.16.1.102/forum/;
       proxy_set_header  X-Real-IP $remote_addr;        # 其实就是添加此行
}

而后重新载入Nginx代理服务器
[root@nginx 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
Reloading nginx:                                           [  OK  ]

再来用浏览器访问一下,可以看到仍然没有记录真实客户端的ip地址
[root@web1 ~]# tail /var/log/httpd/access_log
172.16.1.101 - - [20/Jan/2016:13:57:21 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
172.16.1.101 - - [20/Jan/2016:13:58:03 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
因为我们web服务器访问日志记录格式中第一项记录的请求客户端的地址,也就是我们的Nginx反向代理服务器地址

修改web服务器端的访问日志格式,修改之前先备份原有的combined模式并注释,将第一个%h修改为%{X-Real-IP}i即可
[root@web1 ~]# vim /etc/httpd/conf/httpd.conf
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

然后重启httpd服务或是重新载入都可以
[root@web1 ~]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

再用浏览器访问一下然后看httpd服务器的访问日志
[root@web1 ~]# tail /var/log/httpd/access_log
172.16.1.101 - - [20/Jan/2016:13:57:21 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
172.16.1.101 - - [20/Jan/2016:13:58:03 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
172.16.1.100 - - [20/Jan/2016:14:09:28 +0800] "GET /bbs/ HTTP/1.0" 200 32 "-" "Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
可以看到客户端真实ip已经记录,这个172.16.1.100就是我自己物理主机的地址


四、Nginx负载均衡

1、准备两台web服务器,配置好页面并进行本地测试。

web1在上面反向代理的示例中已经安装了httpd,这里不需要再安装,只是配置好主页并测试即可
[root@web1 ~]# echo "<h1>web1</h1>" > /var/www/html/index.html
[root@web1 ~]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]
[root@web1 ~]# curl localhost
<h1>web1</h1>

web2
[root@web2 ~]# yum install -y httpd 
[root@web2 ~]# echo "<h1>web2</h1>" > /var/www/html/index.html
[root@web2 ~]# service httpd start
Starting httpd:                                            [  OK  ]
[root@web2 ~]# curl localhost
<h1>web2</h1>

2、配置Nginx提供负载均衡功能

首先定义一个upstream组,注意,此upstream需定义在server段之外
[root@nginx nginx]# pwd
/etc/nginx
[root@nginx nginx]# vim nginx.conf
upstream webservers {
        server 172.16.1.102 weight=1;
        server 172.16.1.103 weight=1;
} 
    
然后再修改location段为如下所示
location / {
        proxy_pass http://webservers;
        proxy_set_header  X-Real-IP $remote_addr;
} 

重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]

用浏览器访问一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_03


再刷新一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Nginx_04

可以看到,已经实现了简单的负载均衡效果


3、为Nginx增加上游服务器的健康状态监测功能

修改配置文件中upstream段为如下所示
[root@nginx nginx]# vim nginx.conf    
upstream webservers {
        server 172.16.1.102 weight=1 max_fails=2 fail_timeout=2s;
        server 172.16.1.103 weight=1 max_fails=2 fail_timeout=2s;
}

然后重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]

用浏览器访问一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_03

再刷新一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_06

此时停止web1上的httpd服务,一直刷新,显示的一直都是web2

[root@web1 ~]# service httpd stop
Stopping httpd:                                            [  OK  ]

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_06

再让web1上的httpd服务启动起来,可以看到,web1重新被加入进来了

[root@web1 ~]# service httpd start
Starting httpd:                                            [  OK  ]

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_03

再刷新一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_06

4、为Nginx增加sorry_server

修改配置文件中upstream段为如下所示
[root@nginx nginx]# vim nginx.conf    
upstream webservers {
        server 172.16.1.102 weight=1 max_fails=2 fail_timeout=2s;
        server 172.16.1.103 weight=1 max_fails=2 fail_timeout=2s;
        server 127.0.0.1:8080 backup;
}

再在配置文件中定义一个server
server {
        listen 8080;
        server_name localhost;
        root /var/www/mantainance;
        index index.html;
}

接着创建维护页面目录及文件
[root@nginx nginx]# mkdir /var/www/mantainance
[root@nginx nginx]# echo "<h1>Mantainance Time</h1>" > /var/www/mantainance/index.html

然后重新载入nginx
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx 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
Reloading nginx:                                           [  OK  ]

此时停掉web1和web2上的httpd服务
[root@web1 ~]# service httpd stop
Stopping httpd:                                            [  OK  ]
[root@node2 ~]# service httpd stop
Stopping httpd:                                            [  OK  ]

再使用浏览器访问一下

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_10

此时再上线web1
[root@web1 ~]# service httpd start
Starting httpd:                                            [  OK  ]

浏览器刷新

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Nginx_11

再上线web2
[root@web2 ~]# service httpd start
Starting httpd:                                            [  OK  ]

浏览器刷新

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_12

可以看到,当所有的web服务器都宕机时,Nginx自身会加入sorry_server

补充知识1
nginx支持三种调度算法:ip_hash(相当于LVS的sh),round_robin(相当于LVS的rr和wrr),least_conn(相当于LVS的lc)
要想使用ip_hash算法,直接在upstream段中定义ip_hash即可,但是用ip_hash时,不能定义sorry_server

补充知识2
统计80端口服务的每种连接状态数目
[root@nginx nginx]# netstat -tan | awk '/:80\>/{S[$NF]++}END{for(A in S) {print A,S[A]}}'


五、Nginx缓存功能

1、缓存功能模块相关指令介绍

Nginx的缓存功能也是跟反向代理功能使用的是同一个模块:ngx_http_proxy_module
Nginx的缓存由两个部分组成
    共享内存:存储键和缓存对象元数据
    磁盘空间:缓存数据

缓存功能所用到的几个常用指令语法如下
1、proxy_cache
Syntax:	proxy_cache zone | off;
Default:	
proxy_cache off;
Context:	http, server, location
zone指的是启用某个共享内存区域的缓存功能

2、proxy_cache_path
Syntax:	proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size 
[inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time] 
[purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default:	—
Context:	http
path指的是缓存数据的存储路径
levels指的是nginx的缓存目录层次级别,最多有3级,并且每级最多用2个字符定义
keys_zone指的是缓存的共享内存名称,也是proxy_cache后面所引用的名称,size指明这段共享内存区域大小
max_size指的是缓存数据的磁盘空间大小

3、proxy_cache_valid
Syntax:	proxy_cache_valid [code ...] time;
Default:	—
Context:	http, server, location
code指的是http响应报文的状态码
time指的是对于某种code所缓存的时长

2、为Nginx增加缓存功能

首先编辑配置文件,定义proxy_cache_path,此指令跟upstream指令一样需定义在server段之外
[root@nginx nginx]# vim nginx.conf
proxy_cache_path /nginx/cache/first levels=1:2 keys_zone=first:20m max_size=1g;

上面只是定义缓存功能,但是还没有启用,所以我们需要在某个location中定义明确启用哪个缓存
[root@nginx nginx]# vim nginx.conf
location / {
            proxy_pass http://webservers;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_cache first;            # proxy_cache后面跟的是keys_zone中所定义的名称 
            proxy_cache_valid 200 10m;    # 表示响应报文状态码为200的缓存10分钟      
}

检查是否有语法错误
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: [emerg] mkdir() "/nginx/cache/first" failed (2: No such file or directory)
nginx: configuration file /etc/nginx/nginx.conf test failed

创建缓存目录
[root@nginx nginx]# mkdir -pv /nginx/cache/first
mkdir: created directory `/nginx'
mkdir: created directory `/nginx/cache'
mkdir: created directory `/nginx/cache/first'

检查是否有语法错误
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]

3、测试Nginx的缓存功能

为了方便测试是否命中缓存,在配置文件中的server段中定义一个指令
[root@nginx nginx]# vim nginx.conf
        add_header X-Cache "$upstream_cache_status from $server_addr";

检查是否有语法错误
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]        
        
首先查看我们的缓存目录,可以看到此时是空的,里面并没有缓存任何内容
[root@nginx nginx]# ls /nginx/cache/first/f/63/

接着用浏览器访问看看,此时是第一次访问,所以是X-Cache为MISS

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_13

此时再次查看缓存目录,可以看到缓存已经有了
[root@nginx nginx]# cat /nginx/cache/first/f/63/681ad4c77694b65d61c9985553a2763f 
aVn.VRVh3"c04fd-e-529be6a44b2a8"
KEY: http://webservers/
HTTP/1.1 200 OK
Date: Wed, 20 Jan 2016 13:53:22 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Wed, 20 Jan 2016 06:51:26 GMT
ETag: "c04fd-e-529be6a44b2a8"
Accept-Ranges: bytes
Content-Length: 14
Connection: close
Content-Type: text/html; charset=UTF-8

<h1>web1</h1>

再刷新一下浏览器,可以看到我们始终是被定向至web2
因为我们在配置文件中定义了对于状态码为200的缓存10m,并且此时X-Cache显示为命中

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_14

补充知识:
Nginx常用的三种缓存
    open_log_cache:日志缓存,可以降低磁盘io
	open_file_cache:文件缓存,加速nginx响应过程
	fastcgi_cache:后端应用程序服务器生成的结果缓存,这个要慎用


六、Nginx之URL重写

1、编辑配置文件,定义rewrite规则

这里为了不受上面负载均衡的示例,恢复配置文件到最初安装nginx时候的状态
[root@nginx ~]# cd /etc/nginx/
[root@nginx nginx]# mv nginx.conf{,.back}
[root@nginx nginx]# cp nginx.conf.default nginx.conf

编辑配置文件,在location段中增加如下rewrite一行
[root@nginx nginx]# vim nginx.conf    
location / {
            root   html;
            index  index.html index.htm;
            rewrite ^/bbs/(.*)$ http://172.16.1.102/forum/$1;
}

测试是否有语法错误
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]

2、在web服务器上配置好相应的目录及页面文件

[root@web1 ~]# cd /var/www/html/
[root@web1 html]# ls
index.html
[root@web1 html]# mkdir forum
[root@web1 html]# echo "<h1>Forum On Apache Server</h1>" > forum/index.html

本地测试访问一下
[root@web1 html]# curl http://172.16.1.102/forum/
<h1>Forum On Apache Server</h1>

3、浏览器访问测试

在浏览器地址栏中输入http://172.16.1.101/bbs,页面直接被重定向至172.16.1.102/forum

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_15

4、配置永久重定向

Nginx编辑配置文件,将rewrite一行修改为如下所示
[root@nginx nginx]# vim nginx.conf
            rewrite ^/bbs(.*)$ /forum/$1;

本地配置好forum目录及页面文件           
[root@nginx ~]# cd /usr/html/
[root@nginx html]# ls
50x.html  index.html
[root@nginx html]# mkdir forum
[root@nginx html]# echo "<h1>Forum On Nginx Server</h1>" > forum/index.html

测试是否有语法错误
[root@nginx nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入nginx
[root@nginx 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
Reloading nginx:                                           [  OK  ]

5、浏览器访问测试

在浏览器地址栏中输入http://172.16.1.101/bbs,可以看到Status code为200,这种也叫隐形重定向一般跨服务器的是临时重定向,服务器内部的则是永久重定向。

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_Linux_16


七、Nginx读写分离

1、需求分析及拓扑图

需求分析

构建一个论坛,前端是个Nginx,实现读写分离,将用户的写请求(上传附件之类的操作)定向至web1,读请求定向至web2。web1和web2之间使用rsync+inotify或者sersync同步用户上传的文件,从而实现用户不管被定向至哪个web服务器,都能访问到自己之前上传的文件

拓扑图

Ngxin详解之反向代理、负载均衡、缓存、URL重写及读写分离_反向代理_17

2、WebDAV概念介绍

WebDAV (Web-based Distributed Authoring and Versioning) 一种基于 HTTP 1.1协议的通信协议。它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对Web Server直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。


3、修改web1的配置文件,使其支持put方法

修改配置文件,启用如下两个模块
[root@web1 ~]# vim /etc/httpd/conf/httpd.conf 
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

再在网页的根目录即Directory段中定义一个Dav指令
<Directory "/var/www/html">
Dav on
    Options Indexes FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

测试语法是否有错误
[root@web1 ~]# httpd -t
Syntax OK

重新启动httpd服务
[root@web1 ~]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

4、测试两个web是否支持读和写请求

测试两个web的读请求是否正常
[root@web1 ~]# curl http://172.16.1.102
<h1>web1</h1>
[root@web1 ~]# curl http://172.16.1.103
<h1>web2</h1>

测试web1是否能够支持写请求,也就是上传操作
[root@web1 ~]# curl -T /etc/fstab http://172.16.1.102
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /fstab
on this server.</p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at 172.16.1.102 Port 80</address>
</body></html>

提示403 Forbidden,没有权限
因为/var/www/html的属主属组是root,而运行httpd服务的是apache用户,加上写权限即可
[root@web1 ~]# setfacl -m u:apache:rwx /var/www/html/

可以看到状态码为201,并且文件已经上传到了172.16.1.102上,也就是我们定义的那个能写的web服务器
[root@web1 ~]# curl  -T /etc/issue http://172.16.1.102
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>201 Created</title>
</head><body>
<h1>Created</h1>
<p>Resource /issue has been created.</p>
<hr />
<address>Apache/2.2.15 (CentOS) Server at 172.16.1.102 Port 80</address>
</body></html>

测试是否成功上传
[root@web1 ~]# curl http://172.16.1.102/issue
CentOS release 6.5 (Final)
Kernel \r on an \m

再来测试web2是否能够支持写请求,我们的目的是web1能上传,web2不能上传,只能读
[root@web1 ~]# curl -T /etc/fstab http://172.16.1.103
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>405 Method Not Allowed</title>
</head><body>
<h1>Method Not Allowed</h1>
<p>The requested method PUT is not allowed for the URL /fstab.</p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at 172.16.1.103 Port 80</address>
</body></html>
可以看到状态码为405而不是403,说不支持这种方法,因为我们在httpd的配置文件并没有定义它可以上传

5、修改前端Nginx配置,使其实现读写分离功能

编辑配置文件,在location段中定义
[root@nginx ~]# vim /etc/nginx/nginx.conf
location / {
            proxy_pass http://172.16.1.103;
            if ($request_method = "PUT") {
                proxy_pass http://172.16.1.102;
            }
}

测试是否有语法错误
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入nginx
[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
Reloading nginx:                                           [  OK  ]

6、测试Nginx的读写分离功能

首先测试读请求,可以看到我们的读请求被定向至web2上
[root@nginx nginx]# curl http://172.16.1.101
<h1>web2</h1>
[root@nginx nginx]# curl http://172.16.1.101
<h1>web2</h1>
[root@nginx nginx]# curl http://172.16.1.101
<h1>web2</h1>
[root@nginx nginx]# curl http://172.16.1.101
<h1>web2</h1>
[root@nginx nginx]# curl http://172.16.1.101
<h1>web2</h1>

再来测试写请求
[root@nginx ~]# curl -T /etc/fstab http://172.16.1.101
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>201 Created</title>
</head><body>
<h1>Created</h1>
<p>Resource /fstab has been created.</p>
<hr />
<address>Apache/2.2.15 (CentOS) Server at 172.16.1.102 Port 80</address>
</body></html>

访问测试一下
[root@nginx ~]# curl http://172.16.1.102/fstab

#
# /etc/fstab
# Created by anaconda on Fri Aug 28 10:30:25 2015
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/vg_centos6-lv_root /                       ext4    defaults        1 1
UUID=7a79d653-e9b7-43f2-a2c1-e41af29b3f5d /boot                   ext4    defaults        1 2
/dev/mapper/vg_centos6-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
/dev/myvg/mydata	/mydata			ext4    defaults	0 0
可以看到已经成功上传到了web1上,此时就实现了读写分离功能
我这里只使用了一个读服务器,其实可以定义一组服务器用作读,Nginx同时实现读写分离和负载均衡