1、傳統web訪問模型
(1)傳統web訪問模型完成一次請求的步驟
1)用戶發起請求
2)服務器接受請求
3)服務器處理請求(壓力最大)
4)服務器響應請求
(2)傳統模型缺點
單點故障;
單台服務器資源有限(客戶端則是無限的);
單台服務器處理耗時長(客戶等待時間過長);
(3)傳統模型優化——單點故障解決方案
-
優化方案一:部署一台備份服務器,宕機直接切換 該方案可以有效解決服務器故障導致的單點故障,但且服務器利用率低、成本高,切換不及時,且無法解決服務器業務壓力問題。
-
優化方案二:部署多台服務器,根據DNS的輪詢解析機制去實現用戶分發 優勢是用戶處理速度得到了提升,但是當其中一台故障,dns並不會知道它故障了,依然將請求分給這個服務器,導致一部分用戶訪問不了業務。
2、並行處理解決方案
1)DNS輪詢解析方案
2)多機陣列——集群模式
圖中,前面兩台服務器負責接受請求和分發請求,它自己並不處理請求,將請求分發給后面的業務服務器來處理。業務服務器處理完請求后,將請求發還給分發器,再由分發器將請求發送給客戶,因此分發器還承擔了響應請求的任務。
由此可見之前傳統模型中服務器端需要承擔的服務器接收請求和響應請求都交給分發器處理了,而業務壓力最大的處理請求則交給業務服務器完成。
分發器和dns雖然都是進行了分發的工作,但不同點在於分發器是自己部署的服務器,而DNS都是使用的運營商的,因此可以調整分發器的邏輯判斷規則。
3、集群
-
計算機集群簡稱集群,是一種計算機系統, 它通過一組松散集成的計算機軟件或硬件連接起來高度緊密地協作完成計算工作。在某種意義上,他們可以被看作是一台計算機。 (百度解釋)
-
將多個物理機器組成一個邏輯計算機,實現負載均衡和容錯。
組成要素:
1)VIP: 給分發器的一個虛擬IP(Virtual IP Address)
2)分發器:nginx
3)數據服務器:web服務器
4、Nginx集群原理
在Nginx集群中Nginx扮演的角色是:分發器。
任務:接受請求、分發請求、響應請求。
功能模塊:
1)ngx_http_upstream_module:基於應用層(七層)分發模塊
2)ngx_stream_core_module:基於傳輸層(四層)分發模塊(1.9開始提供該功能)
(1)Nginx集群的實質
Nginx集群其實是:虛擬主機+反向代理+upstream分發模塊組成的。
虛擬主機:負責接受和響應請求。
反向代理:帶領用戶去數據服務器拿數據。
upstream:告訴nginx去哪個數據服務器拿數據。
(2)數據走向(請求處理流程)
1)虛擬主機接受用戶請求
2)虛擬主機去找反向代理(問反向代理去哪拿數據)
3)反向代理讓去找upstream
4)upstream告訴一個數據服務器IP
5)Nginx去找數據服務器,並發起用戶的請求
6)數據服務器接受請求並處理請求
7)數據服務器響應請求給Nginx
8)Nginx響應請求給用戶
二、使用Nginx分發器構建一個WEB集群
1、環境准備
實驗機 : Vmware 虛擬機 1核1G
網卡:橋接
系統:centos7.5
防火牆:關閉
Selinux:關閉
網段:192.168.199.0/24
准備四台實驗機:都安裝nginx服務,兩台當作分發器,兩台當作web服務器。
主機名 | IP | 角色 |
---|---|---|
Master | 192.168.199.226 | 主分發器 |
Backup | 192.168.199.227 | 備分發器 |
Web01 | 192.168.199.228 | 數據服務器1 |
Web02 | 192.168.199.229 | 數據服務器2 |
2、配置web業務機器
(1)nginx安裝腳本
下載nginx包
wget http://nginx.org/download/nginx-1.15.5.tar.gz -P /usr/local
在web01和web02安裝nginx
在master安裝nginx
(2)配置web服務器操作測試
在web01寫入
echo web01 > /usr/local/nginx/html/index.html # 寫入頁面
在web02寫入
echo web02 > /usr/local/nginx/html/index.html # 寫入頁面
在master主分發器測試,可以打開web業務服務器
[root@master ~]# elinks http://192.168.199.228 -dump web1 [root@master ~]# elinks http://192.168.199.229 -dump web02 [root@master ~]#
3、配置分發器(輪詢方式分發)
upstream語法
upstream name {...},而且只能配置在http中
設置主分發器master的配置文件
[root@master ~]# cd /usr/local/nginx # 清除空行和注釋項 [root@master nginx]# sed -i '/#/d' ./conf/nginx.conf [root@master nginx]# sed -i '/^$/d' ./conf/nginx.conf [root@master nginx]# vi ./conf/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; upstream web{ # 名為web的反向代理群組 server 192.168.199.228; server 192.168.199.229; } server { listen 80; server_name localhost; location / { proxy_pass http://web; # 去找反向代理 include proxy_params; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
手動創建proxy_params文件,文件中存放代理的請求頭相關參數
#包含語法參數,將一個配置文件添加到當前虛擬主機生效,這個文件要手動創建 #這個proxy_params文件創建在/usr/local/nginx/conf底下 nclude proxy_params;
也可以寫絕對路徑
[root@master conf]# vi proxy_params proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 30; proxy_send_timeout 60; proxy_read_timeout 60; proxy_buffering on; proxy_buffer_size 32k; proxy_buffers 4 128k; ~ "proxy_params" 10L, 274C written [root@master conf]# ls fastcgi.conf mime.types scgi_params.default fastcgi.conf.default mime.types.default uwsgi_params fastcgi_params nginx.conf uwsgi_params.default fastcgi_params.default nginx.conf.default win-utf koi-utf proxy_params koi-win scgi_params
重啟master主分發器
[root@master nginx]# killall nginx [root@master nginx]# ./sbin/nginx [root@master nginx]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nginx 2808 root 6u IPv4 80432 0t0 TCP *:http (LISTEN) nginx 2809 nobody 6u IPv4 80432 0t0 TCP *:http (LISTEN) [root@master nginx]#
4、集群分發測試(默認輪詢)
客戶端訪問分發器地址,默認按照輪詢的方式來進行分發。
在web02訪問主分發器
[root@web02 nginx]# elinks http://192.168.199.226 -dump web1 [root@web02 nginx]# elinks http://192.168.199.226 -dump web02 [root@web02 nginx]# elinks http://192.168.199.226 -dump web1 [root@web02 nginx]# elinks http://192.168.199.226 -dump web02 [root@web02 nginx]#
三、Nginx分發算法
集群分發算法:如何將用戶請求按照一定的規律分發給業務服務器。主要分為Nginx集群默認算法和基於請求頭分發算法。
1、Nginx集群默認算法
upstream module
nginx的upstream 目前支持4種方式的分配
(1)輪詢(默認) 每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器down掉,能自動剔除。
(2)weight 指定輪詢幾率,weight和訪問比率成正比,用於后端服務器性能不均的情況,權重越大,訪問的次數就越多。
(3)ip_hash 每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務,好處是可以解決session的問題。
因此前兩種只能處理靜態頁面,而這種方式可以處理動態網站。
(4)fair(第三方) 按后端服務器的響應時間來分配請求,響應時間短的優先分配。
(5)url_hash(第三方) 按訪問url的hash結果來分配請求,使每個url定向到同一個后端服務 ,后端服務器為緩存時比較有效。
2、upstream中設置的Nginx業務服務器狀態
示例
http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream web{ # 名為web的反向代理群組 server 192.168.199.228 down;#設置業務服務器的狀態 down,不參與分發 server 192.168.199.229; } server { listen 80; server_name localhost; location / { proxy_pass http://web; # 去找反向代理 } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
每個設備的狀態設置參數:
-
down 表示當前的server暫時不參與負載;
-
weight 默認為1,weight越大,負載的權重就越大;
-
max_fails 允許請求失敗的次數默認為1,當超過最大次數時,返回proxy_next_upstream模塊定義的錯誤;
-
fail_timeout 失敗超時時間,在連接Server時,如果在超時時間之內超過max_fails指定的失敗次數,會認為在fail_timeout時間內Server不可用,默認為10s
-
backup
備份服務器,業務不忙不會使用這台服務器,業務非常忙會調用這台服務器,其他所有的非backup機器down或者忙的時候,請求backup機器。所以這台機器壓力會最輕。
3、Nginx集群默認算法測試
集群環境與之前完全相同。
主機名 | IP | 角色 |
---|---|---|
Master | 192.168.199.226 | 主分發器 |
Backup | 192.168.199.227 | 備分發器 |
Web01 | 192.168.199.228 | 數據服務器1 |
Web02 | 192.168.199.229 | 數據服務器2 |
(1)輪詢算法分發
注意:在輪詢中,如果服務器down掉了,會自動剔除該服務器。,默認的配置就是輪詢策略。此策略適合服務器配置相當,無狀態且短平快的服務使用。
修改主分發器設置
upstream web { server 192.168.199.228; server 192.168.199.229; } server { listen 80; server_name localhost; location / { proxy_pass http://web; } }
前面已經測試驗證了輪詢算法分發。配置backup參數如下所示:
upstream web { server 192.168.199.228 weight=1; server 192.168.199.229 weight=1 backup; } server { listen 80; server_name localhost; location / { proxy_pass http://web; } }
關停第一個web01節點情況,訪問嘗試:
[root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226-dump web02
(2)基於權重的分發
權重越高分配到需要處理的請求越多。此策略可以和ip_hash結合使用。此策略比較適合服務器的硬件配置差別比較大的情況。
修改主分發器設置
upstream web { # 設置權重比例1:2 server 192.168.199.228 weight=1; server 192.168.199.229 weight=2 ; } server { listen 80; server_name localhost; location / { proxy_pass http://web; } }
訪問測試驗證:
[root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]#
通過權重比例的分配,可以讓性能更強的服務器承擔處理更多的請求。
(3)基於ip_hash分發
ip_hash算法能夠保證來自同樣源地址的請求都分發到同一台主機。 需要注意:在nginx版本1.3.1之前,不能在ip_hash中使用權重(weight)。 ip_hash不能與backup同時使用。默認權重為1。
此策略適合有狀態服務,比如session,當有服務器需要剔除,必須手動down掉。
upstream web { ip_hash; # 指定ip_hash即可 server 192.168.199.228; server 192.168.199.229; } server { listen 80; server_name localhost; location / { proxy_pass http://web; } }
訪問測試驗證:
# 源ip固定,每次訪問的結果都一樣 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 [root@web02 ~]# elinks http://192.168.199.226 -dump web1 #換一台機器,只要ip固定,一直訪問某台服務器 [root@web01 ~]# elinks http://192.168.199.226 -dump web1 [root@web01 ~]# elinks http://192.168.199.226 -dump web1 [root@web01 ~]# elinks http://192.168.199.226 -dump web1 [root@web01 ~]# elinks http://192.168.199.226 -dump web1 [root@web01 ~]# elinks http://192.168.199.226 -dump web1 [root@web01 ~]# elinks http://192.168.199.226 -dump web1
四、Nginx基於請求頭的分發
前面的分發方式都是基於一個集群分發的,而基於請求頭分發一般都是用於多集群分發的。 瀏覽器開發者工具network工具下,獲取請求的請求頭信息如下所示:
Request URL: http://192.168.199.226/ # 請求的URL Request Method: GET # 請求的方法 Status Code: 200 OK Remote Address: 1192.168.199.226:80 Referrer Policy: no-referrer-when-downgrade # 請求的策略 Response headers # 響應頭 Accept-Ranges: bytes Connection: keep-alive Content-Length: 6 Content-Type: text/html Date: Fri, 26 Oct 2018 12:43:02 GMT ETag: "5bd3014d-6" Last-Modified: Fri, 26 Oct 2018 11:58:05 GMT Server: nginx/1.15.5 Request Headers # 請求頭 GET /index.php HTTP/1.1 # 請求方法是GET;域名后面的部分就是路徑,默認是‘/’;使用的HTTP協議是1.1 Host: 192.168.31.43 # 訪問的域名(域名或IP均可) Connection: keep-alive # 長連接 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 用戶瀏覽器的類型 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # 可以接受的數據類型 Accept-Encoding: gzip, deflate # 壓縮 Accept-Language: zh-CN,zh;q=0.9 # 語言
1、基於host分發
基於host分發這種分發方式適用於多集群分發。例如:一個公司有多個網站,每個網站就是一個集群。
在主分發器上設置
http { upstream web1 { # 名為web1的反向代理群組 server 192.168.199.228; } upstream web2 { # 名為web2的反向代理群組 server 192.168.199.229; } server { # web1虛擬主機 listen 80; server_name www.web1.com; # 基於域名分發必須有域名 location / { proxy_pass http://web1; } } server { # web2虛擬主機 listen 80; server_name www.web2.com; # 基於域名分發必須有域名 location / { proxy_pass http://web2; } } }
選擇web02做客戶機,修改hosts文件
[root@web02 ~]# vi -r /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain 4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain 6 192.168.199.226 www.web1.com 192.168.199.226 www.web2.com ~
基於域名的分發測試:
[root@web02 ~]# elinks http://www.web1.com -dump web1 [root@web02 ~]# elinks http://www.web1.com -dump web1 [root@web02 ~]# elinks http://www.web2.com -dump web02 [root@web02 ~]# elinks http://www.web2.com -dump web02 [root@web02 ~]#
2、基於開發語言分發
這種分發方式適用於混合開發的網站,某些大型網站既有php也有jsp,就可以基於開發語言分發。
配置測試環境
選擇web01作為php環境的業務服務器,web02直接還是寫html頁面
在web01上安裝php環境並寫一個簡單的php頁面
#yum安裝php環境 [root@web01 ~]# yum -y install httpd php Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: mirror.sunnyvision.com * extras: mirror.sunnyvision.com * updates: mirror.hostlink.com.hk base ... #關掉nginx,啟動apache [root@web01 ~]# killall nginx [root@web01 ~]# systemctl start httpd [root@web01 ~]# # 編寫php文件到web1 [root@web01 html]# echo "<?php phpinfo();?>" >/var/www/html/index.php [root@web01 html]# #直接訪問web01測試下是否安裝成功 在物理機的瀏覽器訪問 http://192.168.199.228/index.php
在主分發器上設置
# 192.168.199.226分發器上nginx配置 http { upstream php { server 192.168.199.228; } upstream html { server 192.168.199.229; } server { location ~* \.php$ { # 以php結尾的 proxy_pass http://php; } location ~* \.html$ { # 以html結尾的 proxy_pass http://html; } } }
基於開發語言的測試
在物理機訪問分發器的ip192.168.199.226/index.php 可以看到php-info信息頁面
在物理機訪問分發器的ip192.168.199.226/index.html 可以看到web02
3、基於瀏覽器的分發
這種基於瀏覽器的分發,常應用於PC端和移動端區分或瀏覽器適配。
構建測試環境
停止使用web01的apache,啟動nginx
[root@web01 ~]# systemctl stop httpd [root@web01 ~]# lsof -i :80 [root@web01 ~]# /usr/local/nginx/sbin/nginx [root@web01 ~]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nginx 7301 root 6u IPv4 421650 0t0 TCP *:http (LISTEN) nginx 7302 nobody 6u IPv4 421650 0t0 TCP *:http (LISTEN) [root@web01 ~]#
在web01上增加一個虛擬主機
http { server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } server { listen 81; server_name localhost; location / { root web3; index index.html index.htm; } } }
在web01寫入測試文件,重啟nginx,測試是否正常
[root@web01 nginx]# mkdir /usr/local/nginx/web3 [root@web01 nginx]# echo web03 > /usr/local/nginx/web3/index.html [root@web01 nginx]# killall nginx [root@web01 nginx]# ./sbin/nginx [root@web01 nginx]# elinks http://192.168.199.228:81 -dump web03 [root@web01 nginx]#
在主分發器修改配置文件
upstream elinks { server 192.168.199.228; } upstream chrome { server 192.168.199.229; } upstream any { server 192.168.199.228:81; } server { listen 80; server_name www.web1.com; location / { proxy_pass http://any; if ( $http_user_agent ~* Elinks ) { proxy_pass http://elinks; } if ( $http_user_agent ~* chrome ) { proxy_pass http://chrome; } } }
重啟nginx
[root@master nginx]# ./sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@master nginx]# killall nginx [root@master nginx]# ./sbin/nginx [root@master nginx]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nginx 3533 root 6u IPv4 146667 0t0 TCP *:http (LISTEN) nginx 3534 nobody 6u IPv4 146667 0t0 TCP *:http (LISTEN) [root@master nginx]#
在客戶機web02,物理機測試效果
[root@web02 ~]# elinks http://192.168.199.226 -dump web
chrome瀏覽器測試結果
IE瀏覽器測試結果
4、基於源IP分發
像騰訊新聞、58同城等等網站,往往在什么地方登陸則獲取哪個地方的數據。服務器通過源IP匹配判斷,從對應的數據庫中獲取數據。
(1)geo模塊
Nginx的geo模塊不僅可以有限速白名單的作用,還可以做全局負載均衡,可以要根據客戶端ip訪問到不同的server。 geo指令是通過ngx_http_geo_module模塊提供的。默認情況下,nginx安裝時是會自動加載這個模塊,除非安裝時人為的手動添加--without-http_geo_module。 ngx_http_geo_module模塊可以用來創建變量,其值依賴於客戶端IP地址。
geo指令 語法: geo [$address] $variable { ... } 默認值: — 配置段: http 定義從指定的變量獲取客戶端的IP地址。默認情況下,nginx從$remote_addr變量取得客戶端IP地址,但也可以從其他變量獲得。如
geo $remote_addr $geo { default 0; 127.0.0.1 1; } #如果用戶的$remote_addr值是127.0.0.1 則返回 1,即$geo變量的值是1 geo $arg_ttlsa_com $geo { default 0; 127.0.0.1 1; }
(2)基於源IP主分發器的配置
修改主分發器的nginx配置
upstream bj.server { server 192.168.199.228; # web01 } upstream sh.server { server 192.168.199.229; # web02 } upstream default.server { server 192.168.199.228:81; # web03 } geo $geo { # IP庫 default default; 192.168.199.228/32 bj; # 北京 192.168.199.229/32 sh; # 上海 } server { listen 80; server_name www.web1.com; location / { proxy_pass http://$geo.server$request_uri; #$request_uri傳遞原來的url的其他參數 } }
重啟nginx
[root@master nginx]# ./sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@master nginx]# killall nginx [root@master nginx]# ./sbin/nginx [root@master nginx]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nginx 3609 root 6u IPv4 152318 0t0 TCP *:http (LISTEN) nginx 3610 nobody 6u IPv4 152318 0t0 TCP *:http (LISTEN) [root@master nginx]#
訪問測試驗證
在web01測試
[root@web01 nginx]# elinks http://192.168.199.226 -dump web1 [root@web01 nginx]#
在web02測試
[root@web02 ~]# elinks http://192.168.199.226 -dump web02 [root@web02 ~]#
在物理機的測試
參考資料
[1]https://www.cnblogs.com/xiugeng/p/10155283.html