2020-03-31 Nginx反向代理與動(dòng)靜分離集群架構(gòu)應(yīng)用實(shí)踐(四)

1. Nginx負(fù)載均衡配置實(shí)戰(zhàn)

1.1 Nginx負(fù)載均衡反向代理相關(guān)實(shí)踐

1.1.1 實(shí)現(xiàn)為WWW服務(wù)代理

(1)利用upstream定義一組WWW服務(wù)器池
先定義一個(gè)名為“www_pools”的服務(wù)器池,里面有兩臺(tái)Web服務(wù)器,具體內(nèi)容如下:

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

提示
1)默認(rèn)調(diào)度算法是wrr,即權(quán)重輪詢算法。
2)upstream僅僅是定義服務(wù)器池,并不會(huì)直接處理用戶的請求,必須要有其他方式將請求轉(zhuǎn)給這個(gè)服務(wù)器池才行。
3)雖然定義的是WWW服務(wù)器池,但是這個(gè)服務(wù)器池也可以作為BBS等業(yè)務(wù)的服務(wù)器池。因?yàn)楣?jié)點(diǎn)服務(wù)器的虛擬主機(jī)都是根據(jù)訪問的主機(jī)頭字段區(qū)分的。
(2)配置WWW服務(wù)的虛擬主機(jī)Server負(fù)載代理
下面是Nginx反向代理WWW服務(wù)的虛擬主機(jī)配置:

server {
  listen  80;
  server_name  www.etiantian.org;
  location / {
    proxy_pass http://www_pools
    ---通過proxy_pass功能把用戶的請求交由上面反向代理upstream定義的www_pools服務(wù)器池處理
  }
    access_log off;
}

(3)實(shí)際配置并測試效果
Nginx的實(shí)際配置如下:

[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;
        }
   }
}

現(xiàn)在配置hosts解析到代理的IP或VIP上,然后重新加載服務(wù),訪問測試:

[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

從測試結(jié)果中可以看出,已經(jīng)實(shí)現(xiàn)了反向代理、負(fù)載均衡功能,但是有個(gè)問題,出來的結(jié)果并不是帶有www.etiantian.org的字符串,而是BBS的信息,根據(jù)訪問結(jié)果,我們推測是訪問了Web節(jié)點(diǎn)下的BBS虛擬主機(jī),明明代理的是WWW的虛擬主機(jī),為什么結(jié)果是訪問了后端的BBS虛擬主機(jī)了呢?

1.1.2 反向代理多虛擬主機(jī)節(jié)點(diǎn)服務(wù)器企業(yè)案例

對于上述問題,究其原因是,用戶訪問域名時(shí)確實(shí)攜帶了www.etiantian.org主機(jī)頭請求Nginx反向代理服務(wù)器,但是反向代理向下面節(jié)點(diǎn)重新發(fā)起請求時(shí),默認(rèn)并沒有在請求頭里告訴節(jié)點(diǎn)服務(wù)器要找哪臺(tái)虛擬主機(jī),所以,Web節(jié)點(diǎn)服務(wù)器接收到請求后發(fā)現(xiàn)沒有主機(jī)頭信息,因此,就把節(jié)點(diǎn)服務(wù)器的第一個(gè)虛擬主機(jī)發(fā)給了反向代理(而節(jié)點(diǎn)上的第一個(gè)虛擬主機(jī)放置的是BBS,這里是我故意這么放置的)。解決這個(gè)問題的方法,就是當(dāng)反向代理向后重新發(fā)起請求時(shí)要攜帶主機(jī)頭信息,以明確告訴節(jié)點(diǎn)服務(wù)器要找哪個(gè)虛擬主機(jī)。具體的配置很簡單,就是在Nginx代理WWW服務(wù)虛擬主機(jī)配置里增加如下一行配置:

proxy_set_header Host $host;

在代理向后端服務(wù)器發(fā)送的HTTP請求頭中加入host字段信息后,若后端服務(wù)器配置有多個(gè)虛擬主機(jī),它就可以識(shí)別代理的是哪個(gè)虛擬主機(jī)。這是節(jié)點(diǎn)服務(wù)器多虛擬主機(jī)時(shí)的關(guān)鍵配置。整個(gè)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;
    ---在代理向后端服務(wù)器發(fā)送的HTTP請求頭中加入host字段信息,用于當(dāng)后端服務(wù)器配置有多個(gè)虛擬主機(jī)時(shí)識(shí)別代理的是哪個(gè)虛擬主機(jī)。這是節(jié)點(diǎn)服務(wù)器多虛擬主機(jī)時(shí)的關(guān)鍵配置。
        }
   }
}

此時(shí),再重新加載Nginx服務(wù),并用curl進(jìn)行測試檢查:

[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

可以看到這次訪問的結(jié)果和訪問的域名就完全對應(yīng)上了,這樣代理多虛擬主機(jī)的節(jié)點(diǎn)服務(wù)就不會(huì)出問題了。

1.1.3 經(jīng)過反向代理后的節(jié)點(diǎn)服務(wù)器記錄用戶IP的企業(yè)案例

完成了反向代理WWW服務(wù)后,用其他客戶端作為客戶端進(jìn)行測試時(shí)就會(huì)發(fā)現(xiàn)一個(gè)問題,節(jié)點(diǎn)服務(wù)器對應(yīng)的WWW虛擬主機(jī)的訪問日志的第一個(gè)字段記錄的并不是客戶端的IP,而是反向代理服務(wù)器的IP,而最后一個(gè)字段也是“-”。
例如:使用Windows客戶端電腦(IP為192.168.9.19)訪問已經(jīng)解析好代理IP的www.etiantian.org后,去節(jié)點(diǎn)服務(wù)器WWW服務(wù)的日志查看,會(huì)發(fā)現(xiàn)如下日志:

[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節(jié)點(diǎn)服務(wù)器對應(yīng)的WWW虛擬主機(jī)的訪問日志的第一個(gè)字段記錄的并不是客戶端的IP(192.168.9.19),最后一個(gè)字段也是一個(gè)“-”,那么,如何解決這個(gè)問題呢?其實(shí)也很簡單,只需增加如下一行參數(shù):

proxy_set_header X-Forward-For $remote_addr;
---這是反向代理時(shí),節(jié)點(diǎn)服務(wù)器獲取用戶真實(shí)IP的必要功能配置。

在反向代理請求后端節(jié)點(diǎn)服務(wù)器的請求頭中增加獲取的客戶端IP的字段信息,然后節(jié)點(diǎn)后端可以通過程序或者相關(guān)的配置接收X-Forward-For傳過來的真實(shí)用戶的IP信息。
解決上述問題的整個(gè)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;
    ---在代理向后端服務(wù)器發(fā)送的HTTP請求頭中加入X-Forward-For字段信息,用于后端服務(wù)器程序、日志等接收記錄真實(shí)用戶的IP,而不是代理服務(wù)器的IP。
        }
   }
}

重新加載Nginx反向代理服務(wù):

[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

特別注意,雖然反向代理已經(jīng)配置好了,但是節(jié)點(diǎn)服務(wù)器需要的訪問日志如果要記錄用戶的真實(shí)IP,還必須進(jìn)行日志格式配置,這樣才能把代理傳過來的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"參數(shù),如果希望在第一行顯示,可以替換掉第一行的$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節(jié)點(diǎn)服務(wù)器的日志配置后,就可以檢查了,注意,不要用curl從反向代理上檢查,最好換一個(gè)客戶端檢查,這樣才能看到效果。這里使用Windows客戶端電腦(IP為192.168.9.19)訪問已經(jīng)解析好代理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,對應(yīng)Nginx日志格式里的$remote_addr變量,而日志結(jié)尾的192.168.9.19對應(yīng)的是日志格式里的"$http_x_forwarded_for"變量,即接收了前面反向代理配置中“proxy_set_header X-Forward-For $remote_addr;”參數(shù)X-Forwarded-For后的IP了。

X-Forward-For相關(guān)重要參數(shù)說明
1.1.4 和反向代理配置相關(guān)的其他參數(shù)說明

除了具有多虛擬主機(jī)代理以及節(jié)點(diǎn)服務(wù)器記錄真實(shí)用戶IP的功能外,Nginx軟件還提供了相當(dāng)多的作為反向代理和后端節(jié)點(diǎn)服務(wù)器對話的相關(guān)控制參數(shù),由于參數(shù)眾多,最好把這些參數(shù)放到同一個(gè)配置文件里,然后用include方式包含到虛擬主機(jī)配置里,效果如下:

[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     ---把參數(shù)寫成一個(gè)文件,使用include包含,看起來更簡潔、規(guī)范
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 根據(jù)URL中的目錄地址實(shí)現(xiàn)代理轉(zhuǎn)發(fā)

1.2.1 根據(jù)URL中的目錄地址實(shí)現(xiàn)代理轉(zhuǎn)發(fā)說明

案例背景:通過Nginx實(shí)現(xiàn)動(dòng)靜分離,即通過Nginx反向代理配置規(guī)則實(shí)現(xiàn)讓動(dòng)態(tài)資源和靜態(tài)資源及其他業(yè)務(wù)分別由不同的服務(wù)器解析,以解決網(wǎng)站性能、安全、用戶體驗(yàn)等重要問題。
下圖為企業(yè)常見的動(dòng)靜分離集群架構(gòu)圖,此架構(gòu)圖適合網(wǎng)站前端只使用同一個(gè)域名提供服務(wù)的場景。例如,用戶訪問的域名是www.etiantian.org,當(dāng)用戶請求www.etiantian.org/upload/xx地址的時(shí)候,代理會(huì)分配請求到上傳服務(wù)器池(upload_pools)處理數(shù)據(jù);當(dāng)用戶請求www.etiantian.org/x地址的時(shí)候,即不包含上述指定的目錄地址路徑時(shí),代理會(huì)分配請求到默認(rèn)的動(dòng)態(tài)服務(wù)器池請求數(shù)據(jù)(注意:上面的x表示任意路徑)。

動(dòng)靜分離網(wǎng)站集群架構(gòu)
1.2.2 準(zhǔn)備:案例配置實(shí)戰(zhàn)

先進(jìn)行企業(yè)案例需求梳理:

  • 當(dāng)用戶請求www.etiantian.org/upload/x地址時(shí),實(shí)現(xiàn)由上傳服務(wù)器池(upload_pools)處理請求。
  • 當(dāng)用戶請求www.etiantian.org/static/x地址時(shí),實(shí)現(xiàn)由靜態(tài)服務(wù)器池(static_pools)處理請求。
  • 除此之外,對于其他訪問請求全部由默認(rèn)的動(dòng)態(tài)服務(wù)器池(default_pools)處理請求。

了解了需求后,就可以進(jìn)行upstream模塊服務(wù)器池的配置了。static_pools為靜態(tài)服務(wù)器池,有一個(gè)服務(wù)器,地址為192.168.9.7,端口為80。

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

upload_pools為上傳服務(wù)器池,有一個(gè)服務(wù)器,地址為192.168.9.9,端口為80。

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

default_pools為默認(rèn)的服務(wù)器池,即動(dòng)態(tài)服務(wù)器池,有一個(gè)服務(wù)器,地址為192.168.9.14,端口為80。

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

提示:需要增加一臺(tái)測試Web節(jié)點(diǎn)Web03(IP是192.168.9.14),其配置和Web01,Web02一樣。
下面利用location或if語句把不同的URI(路徑)請求分給不同的服務(wù)器池處理,具體配置如下。
方案1:以location方案實(shí)現(xiàn)。將符合static的請求交給靜態(tài)服務(wù)器池static_pools,配置如下:

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

將符合upload的請求交給上傳服務(wù)器池upload_pools,配置如下:

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

不符合上述規(guī)則的請求,默認(rèn)全部交給動(dòng)態(tài)服務(wù)器池default_pools,配置如下:

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

方案2:以if語句實(shí)現(xiàn)。

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為例進(jìn)行講解,Nginx反向代理的實(shí)際配置如下:

[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

不要立刻測試成果,為了實(shí)現(xiàn)上述代理的測試,還需要在Web01和Web02上做節(jié)點(diǎn)的測試配置,才能更好地展示測試效果。
以Web01作為static靜態(tài)服務(wù),地址端口為192.168.9.7:80,需要實(shí)現(xiàn)配置一個(gè)用于測試靜態(tài)的地址頁面,并測試訪問,確定它會(huì)返回正確結(jié)果。

[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

提示:測試的靜態(tài)地址為http://www.etiantian.org/static/index.html,注意,是帶static路徑的地址。

以Web02作為upload上傳服務(wù),地址端口為192.168.9.9:80,需事先配置一個(gè)用于測試上傳服務(wù)的地址頁面,并測試訪問,確定它會(huì)返回正確結(jié)果。操作如下:

[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作為動(dòng)態(tài)服務(wù)節(jié)點(diǎn),地址端口為192.168.9.14:80,同樣需事先配置一個(gè)默認(rèn)的地址頁面,并測試訪問,確定它會(huì)返回正確結(jié)果。操作步驟如下:

[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

以上準(zhǔn)備了3臺(tái)Web節(jié)點(diǎn)服務(wù)器,分別加入到了upstream定義的不同服務(wù)器池,代表3組不同的業(yè)務(wù)集群組,從本機(jī)通過hosts解析各自的域名和IP,然后測試訪問,其地址和實(shí)際訪問的內(nèi)容輸出請對照下表。

測試節(jié)點(diǎn)信息及訪問效果

使用客戶端電腦訪問測試時(shí),最好選用集群以外的機(jī)器,這里先在瀏覽器客戶端的hosts文件里把www.etiantian.org解析到Nginx反向代理服務(wù)器的IP,然后訪問上述URL,看代理是不是把請求正確地轉(zhuǎn)發(fā)到了指定的服務(wù)器上。如果可以得到和表對應(yīng)的內(nèi)容,表示配置的Nginx代理分發(fā)完全正確,如果因?yàn)榉职l(fā)請求到錯(cuò)誤的機(jī)器上就沒有對應(yīng)的URL頁面內(nèi)容了,輸出會(huì)是404錯(cuò)誤。

image.png
image.png
image.png
1.2.3 根據(jù)URL目錄地址轉(zhuǎn)發(fā)的應(yīng)用場景

根據(jù)HTTP的URL進(jìn)行轉(zhuǎn)發(fā)的應(yīng)用情況,被稱為第7層(應(yīng)用層)的負(fù)載均衡,而LVS的負(fù)載均衡一般用于TCP等的轉(zhuǎn)發(fā),因此被稱為第4層(傳輸層)的負(fù)載均衡。
在企業(yè)中,有時(shí)希望只用一個(gè)域名對外提供服務(wù),不希望使用多個(gè)域名對應(yīng)同一個(gè)產(chǎn)品服務(wù),此時(shí)就需要在代理服務(wù)器上通過配置規(guī)則使得匹配不同規(guī)則的請求會(huì)交給不同的服務(wù)器池處理。這類業(yè)務(wù)有以下幾種:

  • 業(yè)務(wù)的域名沒有拆分或者不希望拆分,但希望實(shí)現(xiàn)動(dòng)靜分離、多業(yè)務(wù)服務(wù)分離。
  • 不同的客戶端設(shè)備(如手機(jī)和PC端)使用同一個(gè)域名訪問同一個(gè)業(yè)務(wù)網(wǎng)站,就需要根據(jù)規(guī)則將不同設(shè)備的用戶請求交給后端不同的服務(wù)器處理,以便得到最佳的用戶體驗(yàn)。這也是非常重要的。

1.3 根據(jù)客戶端的設(shè)備(user_agent)轉(zhuǎn)發(fā)

1.3.1 根據(jù)客戶端的設(shè)備(user_agent)轉(zhuǎn)發(fā)的需求

企業(yè)中,對于不同的客戶端設(shè)備,為了讓用戶有更好的訪問體驗(yàn),需要在后端架設(shè)不同的服務(wù)器來滿足不同的客戶端訪問。例如:移動(dòng)客戶端訪問網(wǎng)站,就需要部署單獨(dú)的移動(dòng)服務(wù)器及程序,用戶體驗(yàn)才能更好,而且移動(dòng)端還分蘋果、安卓、iPad等,在傳統(tǒng)的情況下,一般用下面的辦法解決這個(gè)問題。
(1)常規(guī)4層負(fù)載均衡解決方案架構(gòu)
在常規(guī)4層負(fù)載均衡架構(gòu)下,可以使用不同的域名來實(shí)現(xiàn)這個(gè)需求。例如,人為分配讓移動(dòng)端用戶訪問wap.etiantian.org,PC客戶端用戶訪問www.etiantian.org,通過不同域名來引導(dǎo)用戶到指定的后端服務(wù)器,該解決方案的架構(gòu)如下圖所示。

通過域名來引導(dǎo)用戶架構(gòu)示意圖1

通過域名來引導(dǎo)用戶架構(gòu)示意圖2

此解決方案的最大問題就是不同客戶端的用戶要記住對應(yīng)的域名!而絕大多數(shù)用戶只會(huì)記www.etiantian.org,不會(huì)記wap.etiantian.org,這樣一來就會(huì)導(dǎo)致用戶體驗(yàn)不是很好。有沒有辦法讓所有客戶端用戶只訪問一個(gè)統(tǒng)一的www.etiantian.org這個(gè)地址,還能讓不同客戶端設(shè)備都能有更好的訪問體驗(yàn)?zāi)兀慨?dāng)讓有,那就是下面的第7層負(fù)載均衡解決方案。
(2)7層負(fù)載均衡解決方案
在7層負(fù)載均衡架構(gòu)下就可以不需要人為拆分域名了,對外只需要用一個(gè)域名,如www.etiantian.org,然后通過獲取用戶請求中的設(shè)備信息(利用$http_user_agent獲?。鶕?jù)這些信息轉(zhuǎn)給后端合適的服務(wù)器處理,這個(gè)方案最大好處就是不需要讓用戶記憶多個(gè)域名,用戶只需要記住主網(wǎng)站地址www.etiantian.org,剩下的由網(wǎng)站服務(wù)器處理,這樣的思路大大提升了用戶訪問體驗(yàn),這是當(dāng)前企業(yè)網(wǎng)站非常非常常用的解決方案。

通過識(shí)別user_agent分發(fā)請求架構(gòu)示意圖
1.3.2 根據(jù)客戶端設(shè)備(user_agent)轉(zhuǎn)發(fā)請求實(shí)踐

這里還是使用static_pools、upload_pools作為本次實(shí)驗(yàn)的后端服務(wù)器池。下面先根據(jù)電腦客戶端瀏覽器的不同設(shè)置對應(yīng)的匹配規(guī)則。

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;
}

實(shí)踐中完整的配置文件內(nèi)容如下:

[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內(nèi)核的360瀏覽器訪問效果

訪問http://www.etiantian.org/static/返回正常,可以確認(rèn)轉(zhuǎn)發(fā)到了后端的static_pools池。而訪問http://www.etiantian.org/upload/則返回404,因?yàn)闆]有匹配到任何規(guī)則就會(huì)交給默認(rèn)的default_pools池服務(wù)器處理,此時(shí)default_pools服務(wù)器池沒有upload這個(gè)目錄及內(nèi)容頁,所以就返回404錯(cuò)誤了。
使用谷歌瀏覽器返回效果如下圖所示。

谷歌瀏覽器訪問效果圖1

谷歌瀏覽器訪問效果圖2

訪問http://www.etiantian.org/upload/返回正常,可以正確轉(zhuǎn)發(fā)到了后端upload_pools池了。而訪問http://www.etiantian.org/static/時(shí)返回了404,因?yàn)闆]有匹配到任何規(guī)則就會(huì)交給默認(rèn)的default_pools池服務(wù)器處理,此default_pools服務(wù)器池沒有static這個(gè)目錄及內(nèi)容頁,所以就返回404錯(cuò)誤了。
需要特別說明的是,當(dāng)你無法知道客戶端設(shè)備名字字符串(如Chrome、MSIE、Firefox這樣的字符串)時(shí),可以先用這些瀏覽器訪問對應(yīng)的節(jié)點(diǎn)服務(wù)器,然后根據(jù)訪問日志中的$http_user_agent格式記錄的日志確認(rèn):

[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”變量也可針對移動(dòng)端,比如安卓、蘋果、iPad設(shè)備、進(jìn)行匹配去請求指定的服務(wù)器,具體配置如下:

location / {
  if ($http_user_agent ~* "android")
    {
      proxy_pass http://android_pools;    ---這是Android服務(wù)器池,需要提前定義upstream
    }
  if ($http_user_agent ~* "iphone")
    {
      proxy_pass http://iphone_pools;    ---這是iPhone服務(wù)器池,需要提前定義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

針對手機(jī)測試的結(jié)果:

[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;
   }
}

這部分測試可以通過局域網(wǎng)的WIFI功能來實(shí)現(xiàn),用手機(jī)等連接到WIFI,然后訪問服務(wù)器的IP測試就可以了。測試時(shí),請用節(jié)點(diǎn)的第一個(gè)虛擬主機(jī)請求測試,這樣就不需要本地hosts域名解析了,因?yàn)槭謾C(jī)端測試做hosts解析也不容易。
此外,查找移動(dòng)設(shè)備的user_agent對應(yīng)的具體名稱時(shí),還是先用對應(yīng)的設(shè)備通過IP地址訪問節(jié)點(diǎn)服務(wù)器,然后看訪問日志,注意IP訪問只找第一個(gè)虛擬主機(jī)的網(wǎng)站。

1.4 根據(jù)文件擴(kuò)展名實(shí)現(xiàn)代理轉(zhuǎn)發(fā)

除了根據(jù)URI路徑及user_agent轉(zhuǎn)發(fā)外,還可以實(shí)現(xiàn)根據(jù)文件擴(kuò)展名進(jìn)行轉(zhuǎn)發(fā)。

1.4.1 相關(guān)server配置

先看看location方法的匹配規(guī)則:

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

下面是if語句方法的匹配規(guī)則:

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

此部分實(shí)踐方法和前面的根據(jù)URI路徑以及user_agent轉(zhuǎn)發(fā)是相同的。

1.4.2 根據(jù)擴(kuò)展名轉(zhuǎn)發(fā)的應(yīng)用場景

可根據(jù)擴(kuò)展名實(shí)現(xiàn)資源動(dòng)靜分離訪問。例如:圖片、視頻等請求靜態(tài)服務(wù)器池,PHP、JSP等請求動(dòng)態(tài)服務(wù)器池。示例代碼如下:

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;
}

在開發(fā)無法通過程序?qū)崿F(xiàn)動(dòng)靜分離的時(shí)候,運(yùn)維可以根據(jù)資源實(shí)體進(jìn)行動(dòng)靜分離,而不依賴于開發(fā),具體實(shí)現(xiàn)策略是先把后端的服務(wù)器分成不同的組。注意,每組服務(wù)器的程序都是相同的,因?yàn)殚_發(fā)沒有把程序拆開,分組后,在前端代理服務(wù)器上通過講解過的路徑、擴(kuò)展名進(jìn)行規(guī)則匹配,從而實(shí)現(xiàn)請求的動(dòng)靜分離。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容