2020-03-31 Nginx反向代理与动静分离集群架构应用实践(四)

1. Nginx负载均衡配置实战

1.1 Nginx负载均衡反向代理相关实践

1.1.1 实现为WWW服务代理

(1)利用upstream定义一组WWW服务器池
先定义一个名为“www_pools”的服务器池,里面有两台Web服务器,具体内容如下:

upstream www_pools {
  server 10.0.0.7:80 weight=1;
  server 10.0.0.8:80 weight=1;
}

提示
1)默认调度算法是wrr,即权重轮询算法。
2)upstream仅仅是定义服务器池,并不会直接处理用户的请求,必须要有其他方式将请求转给这个服务器池才行。
3)虽然定义的是WWW服务器池,但是这个服务器池也可以作为BBS等业务的服务器池。因为节点服务器的虚拟主机都是根据访问的主机头字段区分的。
(2)配置WWW服务的虚拟主机Server负载代理
下面是Nginx反向代理WWW服务的虚拟主机配置:

server {
  listen  80;
  server_name  www.etiantian.org;
  location / {
    proxy_pass http://www_pools
    ---通过proxy_pass功能把用户的请求交由上面反向代理upstream定义的www_pools服务器池处理
  }
    access_log off;
}

(3)实际配置并测试效果
Nginx的实际配置如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream www_pools {
        server 192.168.9.7:80  weight=1;
        server 192.168.9.9:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
            proxy_pass http://www_pools;
        }
   }
}

现在配置hosts解析到代理的IP或VIP上,然后重新加载服务,访问测试:

[root@lb01 conf]# curl www.etiantian.org
bbs7
[root@lb01 conf]# curl www.etiantian.org
bbs9
[root@lb01 conf]# curl www.etiantian.org
bbs7
[root@lb01 conf]# curl www.etiantian.org
bbs9

从测试结果中可以看出,已经实现了反向代理、负载均衡功能,但是有个问题,出来的结果并不是带有www.etiantian.org的字符串,而是BBS的信息,根据访问结果,我们推测是访问了Web节点下的BBS虚拟主机,明明代理的是WWW的虚拟主机,为什么结果是访问了后端的BBS虚拟主机了呢?

1.1.2 反向代理多虚拟主机节点服务器企业案例

对于上述问题,究其原因是,用户访问域名时确实携带了www.etiantian.org主机头请求Nginx反向代理服务器,但是反向代理向下面节点重新发起请求时,默认并没有在请求头里告诉节点服务器要找哪台虚拟主机,所以,Web节点服务器接收到请求后发现没有主机头信息,因此,就把节点服务器的第一个虚拟主机发给了反向代理(而节点上的第一个虚拟主机放置的是BBS,这里是我故意这么放置的)。解决这个问题的方法,就是当反向代理向后重新发起请求时要携带主机头信息,以明确告诉节点服务器要找哪个虚拟主机。具体的配置很简单,就是在Nginx代理WWW服务虚拟主机配置里增加如下一行配置:

proxy_set_header Host $host;

在代理向后端服务器发送的HTTP请求头中加入host字段信息后,若后端服务器配置有多个虚拟主机,它就可以识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置。整个Nginx代理配置如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream www_pools {
        server 192.168.9.7:80  weight=1;
        server 192.168.9.9:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
            proxy_pass http://www_pools;
        proxy_set_header Host $host;
    ---在代理向后端服务器发送的HTTP请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置。
        }
   }
}

此时,再重新加载Nginx服务,并用curl进行测试检查:

[root@lb01 conf]# nginx -t
nginx: the configuration file /application/nginx-1.16.0//conf/nginx.conf syntax is ok
nginx: configuration file /application/nginx-1.16.0//conf/nginx.conf test is successful
[root@lb01 conf]# nginx -s reload
[root@lb01 conf]# curl www.etiantian.org
www7
[root@lb01 conf]# curl www.etiantian.org
www9

可以看到这次访问的结果和访问的域名就完全对应上了,这样代理多虚拟主机的节点服务就不会出问题了。

1.1.3 经过反向代理后的节点服务器记录用户IP的企业案例

完成了反向代理WWW服务后,用其他客户端作为客户端进行测试时就会发现一个问题,节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并不是客户端的IP,而是反向代理服务器的IP,而最后一个字段也是“-”。
例如:使用Windows客户端电脑(IP为192.168.9.19)访问已经解析好代理IP的www.etiantian.org后,去节点服务器WWW服务的日志查看,会发现如下日志:

[root@web01 ~]# tail -2 /application/nginx/logs/access_www.log 
192.168.9.1 - - [29/Mar/2020:02:28:59 +0800] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "-"
192.168.9.1 - - [29/Mar/2020:02:28:59 +0800] "GET /favicon.ico HTTP/1.1" 404 555 "http://www.etiantian.org/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "-"

Web01节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并不是客户端的IP(192.168.9.19),最后一个字段也是一个“-”,那么,如何解决这个问题呢?其实也很简单,只需增加如下一行参数:

proxy_set_header X-Forward-For $remote_addr;
---这是反向代理时,节点服务器获取用户真实IP的必要功能配置。

在反向代理请求后端节点服务器的请求头中增加获取的客户端IP的字段信息,然后节点后端可以通过程序或者相关的配置接收X-Forward-For传过来的真实用户的IP信息。
解决上述问题的整个Nginx代理配置如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream www_pools {
        server 192.168.9.7:80  weight=1;
        server 192.168.9.9:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
            proxy_pass http://www_pools;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
    ---在代理向后端服务器发送的HTTP请求头中加入X-Forward-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器的IP。
        }
   }
}

重新加载Nginx反向代理服务:

[root@lb01 conf]# nginx -t
nginx: the configuration file /application/nginx-1.16.0//conf/nginx.conf syntax is ok
nginx: configuration file /application/nginx-1.16.0//conf/nginx.conf test is successful
[root@lb01 conf]# nginx -s reload

特别注意,虽然反向代理已经配置好了,但是节点服务器需要的访问日志如果要记录用户的真实IP,还必须进行日志格式配置,这样才能把代理传过来的X-Forwarded-For头信息记录下来,具体配置如下:

[root@web01 ~]# cat /application/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    ---就是这里的"$http_x_forwarded_for"参数,如果希望在第一行显示,可以替换掉第一行的$remote_addr变量。
    server {
    listen      80;
    server_name     bbs.etiantian.org;
    location / {
            root html/bbs;
            index index.html index.htm;
    }
    access_log logs/access_bbs.log main;
    }
    server {
        listen  80;
        server_name www.etiantian.org;
        location / {
            root    html/www;
            index   index.html index.htm;
        }
        access_log  logs/access_www.log main;
    }
}

完成Web01、Web02节点服务器的日志配置后,就可以检查了,注意,不要用curl从反向代理上检查,最好换一个客户端检查,这样才能看到效果。这里使用Windows客户端电脑(IP为192.168.9.19)访问已经解析好代理IP的www.etiantian.org,如下图所示。

[root@web01 ~]# tail -2 /application/nginx/logs/access_www.log 
192.168.9.12 - - [29/Mar/2020:02:54:19 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "192.168.9.19"
192.168.9.12 - - [29/Mar/2020:02:54:42 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "192.168.9.19"

日志里192.168.9.12为反向代理IP,对应Nginx日志格式里的$remote_addr变量,而日志结尾的192.168.9.19对应的是日志格式里的"$http_x_forwarded_for"变量,即接收了前面反向代理配置中“proxy_set_header X-Forward-For $remote_addr;”参数X-Forwarded-For后的IP了。

X-Forward-For相关重要参数说明
1.1.4 和反向代理配置相关的其他参数说明

除了具有多虚拟主机代理以及节点服务器记录真实用户IP的功能外,Nginx软件还提供了相当多的作为反向代理和后端节点服务器对话的相关控制参数,由于参数众多,最好把这些参数放到同一个配置文件里,然后用include方式包含到虚拟主机配置里,效果如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream www_pools {
        server 192.168.9.7:80  weight=1;
        server 192.168.9.9:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
            proxy_pass http://www_pools;
        include proxy.conf;    ---这就是包含的配置
        }
   }
}

[root@lb01 conf]# cat proxy.conf     ---把参数写成一个文件,使用include包含,看起来更简洁、规范
proxy_set_header Host $host;
proxy_set_header X-Forward-For $remote_addr;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

1.2 根据URL中的目录地址实现代理转发

1.2.1 根据URL中的目录地址实现代理转发说明

案例背景:通过Nginx实现动静分离,即通过Nginx反向代理配置规则实现让动态资源和静态资源及其他业务分别由不同的服务器解析,以解决网站性能、安全、用户体验等重要问题。
下图为企业常见的动静分离集群架构图,此架构图适合网站前端只使用同一个域名提供服务的场景。例如,用户访问的域名是www.etiantian.org,当用户请求www.etiantian.org/upload/xx地址的时候,代理会分配请求到上传服务器池(upload_pools)处理数据;当用户请求www.etiantian.org/x地址的时候,即不包含上述指定的目录地址路径时,代理会分配请求到默认的动态服务器池请求数据(注意:上面的x表示任意路径)。

动静分离网站集群架构
1.2.2 准备:案例配置实战

先进行企业案例需求梳理:

  • 当用户请求www.etiantian.org/upload/x地址时,实现由上传服务器池(upload_pools)处理请求。
  • 当用户请求www.etiantian.org/static/x地址时,实现由静态服务器池(static_pools)处理请求。
  • 除此之外,对于其他访问请求全部由默认的动态服务器池(default_pools)处理请求。

了解了需求后,就可以进行upstream模块服务器池的配置了。static_pools为静态服务器池,有一个服务器,地址为192.168.9.7,端口为80。

upstream static_pools {
  server 192.168.9.7:80  weight=1;
}

upload_pools为上传服务器池,有一个服务器,地址为192.168.9.9,端口为80。

upstream upload_pools {
  server 192.168.9.9:80  weight=1;
}

default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.9.14,端口为80。

upstream default_pools {
  server 192.168.9.14:80  weight=1;
}

提示:需要增加一台测试Web节点Web03(IP是192.168.9.14),其配置和Web01,Web02一样。
下面利用location或if语句把不同的URI(路径)请求分给不同的服务器池处理,具体配置如下。
方案1:以location方案实现。将符合static的请求交给静态服务器池static_pools,配置如下:

location /static/ {
  proxy_pass http://static_pools;
  include proxy.conf;
}

将符合upload的请求交给上传服务器池upload_pools,配置如下:

location /upload/ {
  proxy_pass http://upload_pools;
  include proxy.conf;
}

不符合上述规则的请求,默认全部交给动态服务器池default_pools,配置如下:

location / {
  proxy_pass http://default_pools;
  include proxy.conf;
}

方案2:以if语句实现。

if ($request_uri ~* "^/static/(.*)$")
{
  proxy_pass http://static_pools/$1;
}
if ($request_uri ~* "^/upload/(.*)$")
{
  proxy_pass http://upload_pools/$1;
}
location / {
  proxy_pass http://default_pools;
  include proxy.conf;
}

下面以方案1为例进行讲解,Nginx反向代理的实际配置如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream static_pools {
            server 192.168.9.7:80  weight=1;
        }
    upstream upload_pools {
            server 192.168.9.9:80  weight=1;
        }
    upstream default_pools {
             server 192.168.9.14:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
            proxy_pass http://default_pools;
        include proxy.conf;
        }
        location /static/ {
            proxy_pass http://static_pools;
            include proxy.conf;
        }
        location /upload/ {
            proxy_pass http://upload_pools;
            include proxy.conf;
        }
   }
}

重新加载配置生效:

[root@lb01 conf]# nginx -t
nginx: the configuration file /application/nginx-1.16.0//conf/nginx.conf syntax is ok
nginx: configuration file /application/nginx-1.16.0//conf/nginx.conf test is successful
[root@lb01 conf]# nginx -s reload

不要立刻测试成果,为了实现上述代理的测试,还需要在Web01和Web02上做节点的测试配置,才能更好地展示测试效果。
以Web01作为static静态服务,地址端口为192.168.9.7:80,需要实现配置一个用于测试静态的地址页面,并测试访问,确定它会返回正确结果。

[root@web01 ~]# cd /application/nginx/html/www/
[root@web01 www]# mkdir static
[root@web01 www]# echo static_pools >static/index.html
[root@web01 www]# curl http://www.etiantian.org/static/index.html
---注意:这里的www.etiantian.org是解析过web01本地IP的(/etc/hosts)。
static_pools

提示:测试的静态地址为http://www.etiantian.org/static/index.html,注意,是带static路径的地址。

以Web02作为upload上传服务,地址端口为192.168.9.9:80,需事先配置一个用于测试上传服务的地址页面,并测试访问,确定它会返回正确结果。操作如下:

[root@web02 ~]# cd /application/nginx/html/www/
[root@web02 www]# mkdir upload
[root@web02 www]# echo upload_pools >upload/index.html
[root@web02 www]# curl http://www.etiantian.org/upload/index.html
---注意:这里的www.etiantian.org是解析过web01本地IP的。
upload_pools

提示:测试的上传地址为http://www.etiantian.org/upload/index.html,注意,是带upload路径的地址。

以Web03作为动态服务节点,地址端口为192.168.9.14:80,同样需事先配置一个默认的地址页面,并测试访问,确定它会返回正确结果。操作步骤如下:

[root@web03 ~]# cd /application/nginx/html/www/
[root@web03 www]# echo default_pools >index.html 
[root@web03 www]# curl http://www.etiantian.org    ---这里的www.etiantian.org是解析过Web01本地IP的
default_pools

以上准备了3台Web节点服务器,分别加入到了upstream定义的不同服务器池,代表3组不同的业务集群组,从本机通过hosts解析各自的域名和IP,然后测试访问,其地址和实际访问的内容输出请对照下表。

测试节点信息及访问效果

使用客户端电脑访问测试时,最好选用集群以外的机器,这里先在浏览器客户端的hosts文件里把www.etiantian.org解析到Nginx反向代理服务器的IP,然后访问上述URL,看代理是不是把请求正确地转发到了指定的服务器上。如果可以得到和表对应的内容,表示配置的Nginx代理分发完全正确,如果因为分发请求到错误的机器上就没有对应的URL页面内容了,输出会是404错误。

image.png
image.png
image.png
1.2.3 根据URL目录地址转发的应用场景

根据HTTP的URL进行转发的应用情况,被称为第7层(应用层)的负载均衡,而LVS的负载均衡一般用于TCP等的转发,因此被称为第4层(传输层)的负载均衡。
在企业中,有时希望只用一个域名对外提供服务,不希望使用多个域名对应同一个产品服务,此时就需要在代理服务器上通过配置规则使得匹配不同规则的请求会交给不同的服务器池处理。这类业务有以下几种:

  • 业务的域名没有拆分或者不希望拆分,但希望实现动静分离、多业务服务分离。
  • 不同的客户端设备(如手机和PC端)使用同一个域名访问同一个业务网站,就需要根据规则将不同设备的用户请求交给后端不同的服务器处理,以便得到最佳的用户体验。这也是非常重要的。

1.3 根据客户端的设备(user_agent)转发

1.3.1 根据客户端的设备(user_agent)转发的需求

企业中,对于不同的客户端设备,为了让用户有更好的访问体验,需要在后端架设不同的服务器来满足不同的客户端访问。例如:移动客户端访问网站,就需要部署单独的移动服务器及程序,用户体验才能更好,而且移动端还分苹果、安卓、iPad等,在传统的情况下,一般用下面的办法解决这个问题。
(1)常规4层负载均衡解决方案架构
在常规4层负载均衡架构下,可以使用不同的域名来实现这个需求。例如,人为分配让移动端用户访问wap.etiantian.org,PC客户端用户访问www.etiantian.org,通过不同域名来引导用户到指定的后端服务器,该解决方案的架构如下图所示。

通过域名来引导用户架构示意图1

通过域名来引导用户架构示意图2

此解决方案的最大问题就是不同客户端的用户要记住对应的域名!而绝大多数用户只会记www.etiantian.org,不会记wap.etiantian.org,这样一来就会导致用户体验不是很好。有没有办法让所有客户端用户只访问一个统一的www.etiantian.org这个地址,还能让不同客户端设备都能有更好的访问体验呢?当让有,那就是下面的第7层负载均衡解决方案。
(2)7层负载均衡解决方案
在7层负载均衡架构下就可以不需要人为拆分域名了,对外只需要用一个域名,如www.etiantian.org,然后通过获取用户请求中的设备信息(利用$http_user_agent获取),根据这些信息转给后端合适的服务器处理,这个方案最大好处就是不需要让用户记忆多个域名,用户只需要记住主网站地址www.etiantian.org,剩下的由网站服务器处理,这样的思路大大提升了用户访问体验,这是当前企业网站非常非常常用的解决方案。

通过识别user_agent分发请求架构示意图
1.3.2 根据客户端设备(user_agent)转发请求实践

这里还是使用static_pools、upload_pools作为本次实验的后端服务器池。下面先根据电脑客户端浏览器的不同设置对应的匹配规则。

location / {
  if ($http_user_agent ~* "MSIE")
---如果请求的浏览器为微软IE浏览器(MSIE),则让请求由static_pools池处理
    {
      proxy_pass http://static_pools;
    }
  if ($http_user_agent ~* "Chrome")
---如果请求的浏览器为谷歌浏览器(Chrome),则让请求由upload_pools池处理
    {
      proxy_pass http://upload_pools;
    }
  proxy_pass http://default_pools;
---其他客户端,由default_pools处理
  include proxy.conf;
}

实践中完整的配置文件内容如下:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream static_pools {
            server 192.168.9.7:80  weight=1;
        }
    upstream upload_pools {
            server 192.168.9.9:80  weight=1;
        }
    upstream default_pools {
             server 192.168.9.14:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
      if ($http_user_agent ~* "MSIE")
            {
                proxy_pass http://static_pools;
            }
      if ($http_user_agent ~* "Chrome")
            {
                proxy_pass http://upload_pools;
            }
      proxy_pass http://default_pools;
      include proxy.conf;
        }
    access_log off;
   }
}

使用微软IE浏览器访问的效果如下图所示。

使用微软IE内核的360浏览器访问效果

访问http://www.etiantian.org/static/返回正常,可以确认转发到了后端的static_pools池。而访问http://www.etiantian.org/upload/则返回404,因为没有匹配到任何规则就会交给默认的default_pools池服务器处理,此时default_pools服务器池没有upload这个目录及内容页,所以就返回404错误了。
使用谷歌浏览器返回效果如下图所示。

谷歌浏览器访问效果图1

谷歌浏览器访问效果图2

访问http://www.etiantian.org/upload/返回正常,可以正确转发到了后端upload_pools池了。而访问http://www.etiantian.org/static/时返回了404,因为没有匹配到任何规则就会交给默认的default_pools池服务器处理,此default_pools服务器池没有static这个目录及内容页,所以就返回404错误了。
需要特别说明的是,当你无法知道客户端设备名字字符串(如Chrome、MSIE、Firefox这样的字符串)时,可以先用这些浏览器访问对应的节点服务器,然后根据访问日志中的$http_user_agent格式记录的日志确认:

[root@web01 conf]# tail -2 ../logs/access_www.log 
192.168.9.12 - - [31/Mar/2020:05:29:41 +0800] "GET /static/ HTTP/1.0" 200 13 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" "-"
192.168.9.12 - - [31/Mar/2020:05:51:33 +0800] "GET /static/ HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "-"

除了针对浏览器外,上述“$http_user_agent”变量也可针对移动端,比如安卓、苹果、iPad设备、进行匹配去请求指定的服务器,具体配置如下:

location / {
  if ($http_user_agent ~* "android")
    {
      proxy_pass http://android_pools;    ---这是Android服务器池,需要提前定义upstream
    }
  if ($http_user_agent ~* "iphone")
    {
      proxy_pass http://iphone_pools;    ---这是iPhone服务器池,需要提前定义upstream
    }
  proxy_pass http://pc_pools;
  include extra/proxy.conf;
}

提示:可以使用curl的-A功能模拟User_agent。

[root@lb01 conf]# curl -A "android" "http://www.etiantian.org/upload/"
upload_pools
[root@lb01 conf]# curl -A "iphone" "http://www.etiantian.org/static/"
static_pools

针对手机测试的结果:

[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    #upload server
    upstream android_pools {
            server 192.168.9.9:80  weight=1;
        }
    upstream pc_pools {
            server 192.168.9.14:80  weight=1;
        }
    #static server
    upstream iphone_pools {
             server 192.168.9.7:80  weight=1;
    }

    server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
      if ($http_user_agent ~* "android")
            {
                proxy_pass http://android_pools;
            }
      if ($http_user_agent ~* "iphone")
            {
                proxy_pass http://iphone_pools;
            }
      proxy_pass http://pc_pools;
      include proxy.conf;
        }
    access_log off;
   }
}

这部分测试可以通过局域网的WIFI功能来实现,用手机等连接到WIFI,然后访问服务器的IP测试就可以了。测试时,请用节点的第一个虚拟主机请求测试,这样就不需要本地hosts域名解析了,因为手机端测试做hosts解析也不容易。
此外,查找移动设备的user_agent对应的具体名称时,还是先用对应的设备通过IP地址访问节点服务器,然后看访问日志,注意IP访问只找第一个虚拟主机的网站。

1.4 根据文件扩展名实现代理转发

除了根据URI路径及user_agent转发外,还可以实现根据文件扩展名进行转发。

1.4.1 相关server配置

先看看location方法的匹配规则:

location ~ .*.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
  proxy_pass http://static_pools;
  include proxy.conf;
}

下面是if语句方法的匹配规则:

if ($request_uri ~* ".*\.(php|php5)$")
{
  proxy_pass http://php_server_pools;
}
if ($request_uri ~* ".*\.(jsp|jsp*|do|do*)$")
{
  proxy_pass http://java_server_pools;
}

此部分实践方法和前面的根据URI路径以及user_agent转发是相同的。

1.4.2 根据扩展名转发的应用场景

可根据扩展名实现资源动静分离访问。例如:图片、视频等请求静态服务器池,PHP、JSP等请求动态服务器池。示例代码如下:

location ~ .*.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
  proxy_pass http://static_pools;
  include proxy.conf;
}
location ~ .*.(php|php3|php5)$ {
  proxy_pass http://dynamic_pools;
  include proxy.conf;
}

在开发无法通过程序实现动静分离的时候,运维可以根据资源实体进行动静分离,而不依赖于开发,具体实现策略是先把后端的服务器分成不同的组。注意,每组服务器的程序都是相同的,因为开发没有把程序拆开,分组后,在前端代理服务器上通过讲解过的路径、扩展名进行规则匹配,从而实现请求的动静分离。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容