假如你配一個LNMP環境,每次只須要服務10個併發請求,那麼單臺服務器必定會比多個服務器集羣要快。只有當併發或總請求數量超過單臺服務器的承受能力時,服務器集羣纔會體現出優點。php
計算機集羣架構按功能和結構能夠分紅如下幾類:css
提示:
負載均衡集羣和高可用性集羣是互聯網行業經常使用的集羣架構模式,也是咱們要學習的重點。html
負載均衡集羣的做用爲:前端
負載均衡集羣典型的開源軟件包括LVS,Nginx,Haproxy等。以下圖所示:java
提示:
不一樣的業務會有若干秒的切換時間,DB業務明顯長於Web業務切換時間。android
通常是指在集羣中任意一個節點失效的狀況下,該節點上的全部任務會自動轉移到其餘正常的節點上。此過程並不影響整個集羣的運行。nginx
高可用性集羣的做用爲:git
高可用性集羣經常使用的開源軟件包括Keepalived,Heartbeat等,其架構圖以下圖所示:github
高性能計算集羣也稱並行計算。一般,高性能計算集羣涉及爲集羣開發的並行應用程序,以解決複雜的科學問題(天氣預報,石油勘探,核反應模擬等)。高性能計算集羣對外就好像一個超級計算機,這種超級計算機內部由數十至上萬個獨立服務器組成,而且在公共消息傳遞層上進行通訊以運行並行應用程序。在生產環境中實際就是把任務切成蛋糕,而後下發到集羣節點計算,計算後返回結果,而後繼續領新任務計算,如此往復。web
因爲不多用到,在此略
特別提示:
在互聯網網站運維中,比較經常使用的就是負載均衡集羣和高可用性集羣
互聯網企業經常使用的開源集羣軟件有:Nginx,LVS,Haproxy,Keepalived,heartbeat。
互聯網企業經常使用的商業集羣硬件有:F5,Netscaler,Radware,A10等,工做模式至關於Haproxy的工做模式。
淘寶,趕集網,新浪等公司曾使用過Netscaler負載均衡產品。集羣硬件Netscaler的產品圖以下圖所示:
下面是我對同窗們的基本選擇建議,更多的建議等你們學完負載均衡內容後再細分講解。
相比較而言,商業的負載均衡產品成本高,性能好,更穩定,缺點是不能二次開發,開源的負載均衡軟件對運維人員的能力要求較高,若是運維及開發能力強,那麼開源的負載均衡軟件是不錯的選擇,目前的互聯網行業更傾向於使用開源的負載均衡軟件。
負載均衡集羣提供了一種廉價,有效,透明的方法,來擴展網絡設備和服務器的負載,帶寬和吞吐量,同時增強了網絡數據處理能力,提升了網絡的靈活性和可用性。
搭建負載均衡服務的需求以下:
(1)把單臺計算機沒法承受的大規模併發訪問或數據流量分擔到多臺節點設備上,分別進行處理,減小用戶等待響應的時間,提高用戶體驗。
(2)單個重負載的運算分擔到多臺節點設備上作並行處理,每一個節點設備處理結束後,將結果彙總,返回給用戶,系統處理能力獲得大幅度提升。
(3)7*24小時的服務保證,任意一個或多個有限後面節點設備宕機,不能影響業務。
在負載均衡集羣中,同組集羣的全部計算機節點都應該提供相同的服務。集羣負載均衡器會截獲全部對該服務的入站請求。而後將這些請求儘量地平均地分配在全部集羣節點上。
本節先帶同窗們一塊兒操做實戰,讓同窗們對Nginx負載均衡有一個初步的概念,而後再繼續深刻講解Nginx負載均衡的核心知識應用。
上圖是快速實踐Nginx負載均衡的邏輯架構圖
在上圖中,全部用戶的請求統一發送到Nginx負載均衡器,而後由負載均衡器根據調度算法來請求Web01和Web02
HOSTNAME | IP | 說明 |
---|---|---|
lb01 | 192.168.103.121 | Nginx主負載均衡器 |
lb02 | 192.168.103.122 | Nginx副負載均衡器 |
web01 | 192.168.103.123 | Web01服務器 |
web02 | 192.168.103.124 | Web02服務器 |
hostname lb01
hostname lb02
hostname web01
hostname web02
在 web01 與 web02 上安裝 apache
# 安裝apache [root@web01 ~]# yum install httpd -y [root@web01 init.d]# service httpd start [root@web02 ~]# yum install httpd -y [root@web02 init.d]# service httpd start # 查看是否啓動 [root@web02 ~]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME httpd 11393 root 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11394 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11395 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11396 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11397 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11409 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11410 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11411 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11412 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11413 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11414 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) # 修改index.html頁內容 [root@web01 /]# echo 192.168.103.123 >/var/www/html/index.html [root@web02 /]# echo 192.168.103.124 >/var/www/html/index.html
下面將在以上4臺服務器上安裝Nginx,這裏只給出安裝的命令部分。
# 安裝上傳下載組件 [root@lb01 /]# yum install lrzsz -y [root@lb02 /]# yum install lrzsz -y [root@web01 /]# yum install lrzsz -y [root@web02 /]# yum install lrzsz -y
# 安裝pcre與gcc環境依賴 # lb01 [root@lb01 tools]# yum -y install openssl openssl-devel pcre pcre-devel [root@lb01 tools]# rpm -qa openssl openssl-devel pcre pcre-devel [root@lb01 tools]# yum install gcc -y # lb02 [root@lb02 tools]# yum -y install openssl openssl-devel pcre pcre-devel [root@lb02 tools]# rpm -qa openssl openssl-devel pcre pcre-devel [root@lb02 tools]# yum install gcc -y # web01 [root@web01 /]# yum -y install openssl openssl-devel pcre pcre-devel [root@web01 /]# rpm -qa openssl openssl-devel pcre pcre-devel [root@web01 /]# yum install gcc -y # web02 [root@web02 /]# yum -y install openssl openssl-devel pcre pcre-devel [root@web02 /]# rpm -qa openssl openssl-devel pcre pcre-devel [root@web02 /]# yum install gcc -y
# 上傳nginx文件 [root@lb01 ~]# mkdir -p /home/oldboy/tools [root@lb01 ~]# cd /home/oldboy/tools [root@lb01 tools]# rz -y [root@lb01 tools]# tar xf nginx-1.6.2.tar.gz [root@lb01 tools]# cd nginx-1.6.2/ # 建立nginx用戶 [root@lb01 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx # 安裝編譯 [root@lb01 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install # 創建ln連接 [root@lb01 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/ # 啓動nginx [root@lb01 nginx-1.6.2]# nginx # 中止nginx # [root@lb01 nginx-1.6.2]# nginx -s stop # 查看 # [root@lb01 nginx-1.6.2]# lsof -i :80 # 上傳nginx文件 [root@lb02 ~]# mkdir -p /home/oldboy/tools [root@lb02 ~]# cd /home/oldboy/tools [root@lb02 tools]# rz -y [root@lb02 tools]# tar xf nginx-1.6.2.tar.gz [root@lb02 tools]# cd nginx-1.6.2/ # 建立nginx用戶 [root@lb02 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx # 安裝編譯 [root@lb02 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install # 創建ln連接 [root@lb02 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/ # 啓動nginx [root@lb02 nginx-1.6.2]# nginx # 中止nginx # [root@lb02 nginx-1.6.2]# nginx -s stop # 查看 # [root@lb02 nginx-1.6.2]# lsof -i :80
本小節將在兩臺NginxWeb服務器的節點上操做(web01與web02):配置並查看Web服務器的配置結果。
// web01 # 添加本地主機名 [root@web01 /]# cd usr/local/nginx/conf/ [root@web01 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.123 www.yunjisuan.com 192.168.103.123 bbs.yunjisuan.com // web02 # 添加本地主機名 [root@web02 /]# cd usr/local/nginx/conf/ [root@web02 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.124 www.yunjisuan.com 192.168.103.124 bbs.yunjisuan.com
安裝 telnet 可選
// web01 # 添加本地主機名 # 安裝telnet [root@web01 /]# yum install telnet nmap dos2unix -y // web02 # 安裝telnet [root@web02 /]# yum install telnet nmap dos2unix -y
配置nginx
// web01 # 配置nginx [root@web01 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf [root@web01 conf]# egrep -v "#|^$" nginx.conf.default [root@web01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf // web02 # 安裝telnet [root@web02 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf [root@web02 conf]# egrep -v "#|^$" nginx.conf.default [root@web02 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
修改 nginx.conf
// web01 [root@web01 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } } } // web02 [root@web02 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } } }
這裏故意將www虛擬主機放在下面,便於用後面的參數配置測試效果
// web01 [root@web01 conf]# 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 // web02 [root@web02 conf]# 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
// web01 [root@web01 conf]# nginx -s reload [root@web01 conf]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 17429/nginx: master // web02 [root@web02 conf]# nginx -s reload [root@web02 conf]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 17429/nginx: master
// web01 [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs} [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html [root@web01 /]# cat /usr/local/nginx/html/www/index.html 192.168.103.123 192.168.122.1 www [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html 192.168.103.123 192.168.122.1 bbs // web02 [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs} [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html [root@web01 /]# cat /usr/local/nginx/html/www/index.html 192.168.103.124 192.168.122.1 www [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html 192.168.103.124 192.168.122.1 bbs
// web01 [root@web01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 www [root@web01 /]# curl bbs.yunjisuan.com 192.168.103.123 192.168.122.1 bbs // web02 [root@web02 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 www [root@web02 /]# curl bbs.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
配置文檔:http://nginx.org/en/docs/http/ngx_http_upstream_module.html
語法:
upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; server unix:/tmp/backend3; server backup1.example.com:8080 backup; server backup2.example.com:8080 backup; } server { location / { proxy_pass http://backend; } }
測試:(本操做基於lb01和lb02)
添加本地域名 [root@lb01 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.121 www.yunjisuan.com
安裝 telnet (可選)
# 安裝telnet
[root@lb01 conf]# yum install telnet nmap dos2unix -y
# 配置nginx [root@lb01 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
upstream webpools { server 192.168.103.123 weight=5; server 192.168.103.124 weight=5; server 192.168.103.125 weight=5 backup; } server { location / { proxy_pass http://webpools; } }
[root@lb01 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { server 192.168.103.123:80 weight=5; server 192.168.103.124:80 weight=5; server 192.168.103.125:80 weight=5 backup; } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; } } }
注意:upstream名稱不能包含下劃線,不然會報以下錯誤
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> <p>Additionally, a 400 Bad Request error was encountered while trying to use an ErrorDocument to handle the request.</p> </body></html>
[root@lb01 conf]# 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@lb01 conf]# nginx -s reload
[root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
Nginx主配置文件nginx.conf是一個純文本類型的文件(其餘配置文件大多也是如此),它位於Nginx安裝目錄下的conf目錄,整個配置文件是以區塊的形式組織的。通常,每一個區塊以一個大括號「{}」來表示,區塊能夠分爲幾個層次,整個配置文件中Main區位於最上層,在Main區下面能夠有Events區,HTTP區等層級,在HTTP區中又包含有一個或多個Server區,每一個Server區中又可有一個或多個location區,整個Nginx配置文件nginx.conf的主體框架爲:
[root@chensiqi conf]# egrep -v "#|^$" nginx.conf #去掉包含#號和空行的內容 worker_processes 1; #worker進程的數量 error_log logs/error.log; #錯誤日誌(默認沒開) pid logs/nginx.pid; #進程號(默認沒開) events { #事件區塊開始 worker_connections 1024; #每一個worker進程支持的最大鏈接數 } #事件區塊結束 http { #http區塊開始 include mime.types; #Nginx支持的媒體類型庫文件包含 default_type application/octet-stream; #默認的媒體類型 sendfile on; #開啓高效傳輸模式 keepalive_timeout 65; #鏈接超時。 server { #網站配置區域(第一個server第一個虛擬主機站點) listen 80; #提供服務的端口,默認80 server_name www.chensiqi.org; #提供服務的域名主機名 location / { #第一個Location區塊開始 root html; #站點的根目錄(相對於nginx安裝路徑) index index.html index.htm; #默認的首頁文件,多個用空格分開 } error_page 500 502 503 504 /50x.html; #出現對應的http狀態碼時,使用50x.html迴應客戶 location = /50x.html { #Location區塊開始,訪問50x.html root html; #指定對應的站點目錄爲html } } server { #網站配置區域(第二個server第二個虛擬主機站點) listen 80; #提供服務的端口,默認80 server_name bbs.chensiqi.org; #提供服務的域名主機名 location / { #服務區塊 root html; #相對路徑(nginx安裝路徑) index index.html index.htm; } location = /50x.html { #發生錯誤訪問的頁面 root html; } } }
整個nginx配置文件的核心框架以下:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } }
若是是配合動態服務(例如PHP服務),Nginx軟件還會用到擴展的fastcgi相關配置文件,這個配置是經過在Nginx.conf主配置文件中嵌入include命令來實現的,不過默認狀況是註釋狀態,不會生效。
fastcgi.conf配置文件的初始內容以下:
[root@localhost conf]# cat fastcgi.conf fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
[root@localhost conf]# cat fastcgi_params fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
上述未作註釋的目錄或文件是比較少用的,有關動態擴展配置後文講到PHP服務時再來說解。
error_log file level;
常見的日誌級別【debug|info|notice|warn|error|crit|alert|emerg】
生產場景通常是warn|error|crit這三個級別之一,注意不要配置info等較低級別,會帶來巨大磁盤I/O消耗。
error_log的默認值爲:
# default:error_log logs/error.log error;
worker_processes 1; error_log logs/error.log; #很是簡單,通常增長此行便可 events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; include extra/www.conf; include extra/mail.conf; include extra/status.conf; }
默認狀況下Nginx會把全部的訪問日誌生成到一個指定的訪問日誌文件access.log裏,但這樣一來,時間長了就會致使日誌個頭很大,不利於日誌的分析和處理,所以,有必要對Nginx日誌,按天或按小時進行切割,使其分紅不一樣的文件保存。
[root@localhost nginx]# cat /server/scripts/cut_nginx_log.sh #!/bin/bash #日誌切割腳本可掛定時任務,天天00點整執行 Dateformat=`date +%Y%m%d` Basedir="/usr/local/nginx" Nginxlogdir="$Basedir/logs" Logname="access" [ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1 [ -f ${Logname}.log ] || exit 1 /bin/mv ${Logname}.log ${Dateformat}_${Logname}.log $Basedir/sbin/nginx -s reload [root@localhost nginx]# cat >>/var/spool/cron/root << KOF #cut nginx access log by Mr.chen 00 00 * * * /bin/bash /server/scripts/cut_nginx_log.sh >/dev/null 2>&1
語法爲:
location [ = | ~ | ~* | ^~ ] uri {
...
}
上圖是對location語法的說明。上述語法中的URI部分是關鍵,這個URI能夠是普通的字符串地址路徑,或者是正則表達式,匹配成功則執行後面大括號裏的相關命令。正則表達式的前面還能夠有「~」或「~*」等特殊字符。
匹配這兩種特殊字符「~」或「~*」的區別爲:「~」用於區分大小寫(大小寫敏感)的匹配;「~*」用於不區分大小寫的匹配。還能夠用邏輯操做符「!」對上面的匹配取反,即「!~」和「!~*」。此外,「^~」的做用是先進行字符串的前綴匹配(必須之後邊的字符串開頭),若是能匹配到,就再也不進行其餘location的正則匹配了。
location匹配示例
[root@localhost nginx]# cat /usr/local/nginx/conf/extra/www.conf server { listen 80; server_name www.yunjisuan.com; root /var/www/html/wwwcom; location / { return 401; } location = / { return 402; } location = /images/ { return 501; } location /documents/ { return 403; } location ^~ /images/ { return 404; } location ~* \.(gif|jpg|jpeg)$ { return 500; } }
匹配結果
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com 402 #匹配了=的狀況 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/ 402 #匹配了=的狀況 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/xxxx 401 #匹配不到默認匹配 /的狀況 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/ 403 #匹配字符串 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/ 501 #優先匹配=的狀況 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/1.jpg 404 #匹配 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/images/1.jpg 500 #匹配~*的狀況
從多個location的配置匹配能夠看出匹配的優先順序
順序 | 匹配標識的location | 匹配說明 |
---|---|---|
1 | " location = / { " | 精確匹配 |
2 | " location ^~ /images/ { " | 先進行字符串的前綴匹配,若是匹配到就不作正則匹配檢查 |
3 | " loction ~* \.(gif | jpg | jpeg)$ { " | 正則匹配,*爲不區分大小寫 |
4 | " location /documents/ { " | 匹配常規字符串,模糊匹配,若是有正則檢查,正則優先 |
5 | " location / { " | 全部location都不能匹配後的默認匹配原則 |
和Apache等Web服務軟件同樣,Nginx rewrite的主要功能也是實現URL地址重寫。Nginx的rewrite規則須要PCRE軟件的支持,即經過Perl兼容正則表達式語法進行規則匹配。默認參數編譯時,Nginx就會安裝支持rewrite的模塊,可是,也必需要有PCRE軟件的支持。
rewrite ^/(.*) http://www.baidu.com/$1 permanent;
在上述指令中,rewrite爲固定關鍵字,表示開啓一條rewrite匹配規則,regex部分是^(.*),這是一個正則表達式,表示匹配全部,匹配成功後跳轉到http://www.baidu.com/$1 。這裏的$1是取前面regex部分括號裏的內容,結尾的permanent;是永久301重定向標記,即跳轉到後面的http://www.baidu.com/$1 地址上。
rewrite指令的最後一項參數flag標記的說明
在以上的flag標記中,last和break用來實現URL重寫,瀏覽器地址欄的URL地址不變,但在服務器端訪問的程序及路徑發生了變化。redirect和permanent用來實現URL跳轉,瀏覽器地址欄會顯示跳轉後的URL地址。
last和break標記的實現功能相似,但兩者之間有細微的差異,使用alias指令時必須用last標記,使用proxy_pass指令時要使用break標記。last標記在本條rewrite規則執行完畢後,會對其所在的server{...}標籤從新發起請求,而break標記則會在本條規則匹配完成後,終止匹配,再也不匹配後面的規則。
以往咱們是經過別名方式實現yunjisuan.com和www.yunjisuan.com訪問同一個地址的,事實上,除了這個方式外,還可使用nginx rewrite 301 跳轉的方式來實現。實現的配置以下:
[root@localhost nginx]# cat conf/extra/www.conf #www virtualhost by Mr.chen server { listen 80; server_name www.yunjisuan.com; root /var/www/html/wwwcom; location / { index index.html index.htm; } # location = / { # return 402; # } location = /images/ { return 501; } location /documents/ { return 403; } location ^~ /images/ { return 404; } location ~* \.(gif|jpg|jpeg)$ { return 500; } } server{ listen 80; server_name yunjisuan.com; rewrite ^/(.*) http://www.yunjisuan.com/$1 permanent; #當用戶訪問yunjisuan.com及下面的任意內容時,都會經過這條rewrite跳轉到www.yunjisuan.com對應的地址 }
upstream模塊的語法至關簡單,這裏直接上範例給同窗們講。
範例1:基本的upstream配置案例
upstream www_server_pools { # upstream是關鍵字必須有,後面的www_server_pools爲一個Upstream集羣組的名字,能夠本身起名,調用時就用這個名字 server 192.168.103.123:80 weight=5; server 192.168.103.124:80 weight=10; server 192.168.103.125:80 weight=15;
#server關鍵字是固定的,後面能夠接域名(門戶會用)或IP。若是不指定端口,默認是80端口。weight表明權重,數值越大被分配的請求越多,結尾有分號,別忘了 }
範例2:較完整的upstream配置案例
upstream blog_server_pool { server 192.168.103.123; #這行標籤和下行是等價的 server 192.168.103.124:80 weight=1 max_fails=1 fail_timeout=10s; #這行標籤和上一行是等價的,此行多餘的部分就是默認配置,不寫也能夠。 server 192.168.103.125:80 weight=1 max_fails=2 fail_timeout=20s backup; # server最後面能夠加不少參數,具體參數做用看下文的表格 }
範例3:使用域名及socket的upstream配置案例
upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; #域名加端口。轉發到後端的指定端口上 server unix:/tmp/backend3; #指定socket文件 #提示:server後面若是接域名,須要內網有DNS服務器或者在負載均衡器的hosts文件作域名解析。 server 192.168.103.123; server 192.168.103.124:8080; server backup1.example.com:8080 backup; #備份服務器,等上面指定的服務器都不可訪問的時候會啓動,backup的用法和Haproxy中用法同樣 server backup2.example.com:8080 backup; }
若是是兩臺Web服務器作高可用,常規方案就須要keepalived配合,那麼這裏使用Nginx的backup參數經過負載均衡功能就能夠實現Web服務器集羣了,對於企業應用來講,能作集羣就不作高可用。
upstream模塊的內容應放於nginx.conf配置的http{}標籤內,其默認調度節點算法是wrr(weighted round-robin,即權重輪詢)。
下圖爲upstream模塊內部server標籤部分參數說明
提示:
以上參數與專業的Haproxy參數很相似,但不如Haproxy的參數易懂。
來看個示例,以下:
upstream backend { server backend1.example.com weight=5; #若是就是單個Server,不必設置權重 server 127.0.0.1:8080 max_fail=5 fail_timeout=10s; #當檢測次數等於5的時候,5次連續檢測失敗後,間隔10s再從新檢測。 server unix:/tmp/backend3; server backup1.example.com:8080 backup; #熱備機器設置 }
須要特別說明的是,若是是Nginx代理Cache服務,可能須要使用hash算法,此時若宕機,可經過設置down參數確保客戶端用戶按照當前的hash算法訪問,這一點很重要。示例配置以下:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
注意:ip_hash不能與backup共同使用
下面是Haproxy負載均衡器server標籤的配置示例。
#開啓對後端服務器的健康檢測,經過GET /test/index.php來判斷後端服務器的健康狀況 server php_server_1 192.168.103.123:80 cookie 1 check inter 2000 rise 3 fall 3 weight 2 server php_server_2 192.168.103.124:80 cookie 2 check inter 2000 rise 3 fall 3 weight 1 server php_server_bak 192.168.103.125:80 cookie 3 check inter 1500 rise 3 fall 3 backup
上述命令的說明以下:
調度算法通常分爲兩類:
下面介紹一下常見的調度算法。
upstream yunjisuan_lb{ ip_hash; server 192.168.0.223:80; server 192.168.0.224:8080; } upstream backend{ ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; server backend4.example.com; }
注意:
當負載調度算法爲ip_hash時,後端服務器在負載均衡調度中的狀態不能有weight和backup,即便有也不會生效。
upstream yunjisuan_lb{ server 192.168.103.123; server 192.168.103.124; fair; }
upstream yunjisuan_lb { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
http { upstream test { consistent_hash $request_uri; server 127.0.0.1:9001 id=1001 weight=3; server 127.0.0.1:9002 id=1002 weight=10; server 127.0.0.1:9003 id=1003 weight=20; } }
雖然Nginx自己不支持一致性hash算法,但Nginx得分支Tengine支持。詳細可參考http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html
proxy_pass指令屬於 ngx_http_proxy_module 模塊,此模塊能夠將請求轉發到另外一臺服務器,在實際的反向代理工做中,會經過location功能匹配指定的URI,而後把接收到的符合匹配URI的請求經過proxy_pass拋給定義好的upstream節點池。該指令官方地址1見:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
下面proxy_pass的使用案例:
location /name/ { proxy_pass http://127.0.0.1/remote/; }
location /some/path/ { proxy_pass http://127.0.0.1; }
location /name/ { rewrite /name/( [^/]+ ) /username=$1 break; proxy_pass http://127.0.0.1; }
Nginx的代理功能是經過http proxy模塊來實現的。默認在安裝Nginx時已經安裝了http proxy模塊,所以可直接使用http proxy模塊。下面詳細解釋模塊1中每一個選項表明的含義,見下表:
主機名 | IP地址 | 角色說明 |
---|---|---|
lb01 | 192.168.103.121 | nginx主負載均衡 |
lb02 | 192.168.103.122 | nginx從負載均衡 |
Web01 | 192.168.103.123 | nginx web01服務器 |
Web02 | 192.168.103.124 | nginx web02服務器 |
查看lb01的配置文件以下:
// lb01 [root@lb01 /]# cat /usr/local/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 webpools { #默認調度算法wrr,即權重輪詢算法 #雖然定義的www服務器池可是這個服務器池也能夠做爲BBS等業務的服務器池。由於節點服務器的虛擬主機都是根據訪問的主機頭字段區分的。 #若是就是單個Server,不必設置權重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #熱備機器設置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; #經過proxy_pass功能把用過戶的請求交給上面反向代理upstream定義的webpools服務器池處理。 } } }
如今配置hosts解析到代理服務器lb01上,從新加載服務,訪問測試
[root@lb01 /]# tail -2 /etc/hosts 192.168.103.121 www.yunjisuan.com 192.168.103.121 bbs.yunjisuan.com [root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload [root@lb01 /]# tail -2 /etc/hosts 192.168.103.121 www.yunjisuan.com 192.168.103.121 bbs.yunjisuan.com [root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload [root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
從測試結果能夠看出,已經實現了反向代理,負載均衡功能,可是有一個特殊問題,出來的結果並非帶有www的字符串,而是bbs的字符串,根據訪問結果,咱們推測是訪問了Web節點下bbs的虛擬主機,明明代理的是www虛擬主機,爲何結果是訪問了後端的bbs虛擬主機了呢?問題又該如何解決?請同窗們繼續往下看。
上一節代理的結果不對,究其緣由是當用戶訪問域名時確實是攜帶了www.yunjisuan.com主機頭請求Nginx反向代理服務器,可是反向代理向下面節點從新發起請求時,默認並無在請求頭裏告訴節點服務器要找哪臺虛擬主機,因此,Web節點服務器接收到請求後發現沒有主機頭信息,所以,就把節點服務器的第一個虛擬主機發給了反向代理了(節點上第一個虛擬主機放置的是故意這樣放置的bbs)。解決這個問題的方法,就是當反向代理向後從新發起請求時,要攜帶主機頭信息,以明確告訴節點服務器要找哪一個虛擬主機。具體的配置很簡單,就是在Nginx代理www服務虛擬主機配置裏增長以下一行配置便可:
proxy_set_header host $host;
在代理向後端服務器發送的http請求頭中加入host字段信息後,若後端服務器配置有多個虛擬主機,它就能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。整個Nginx代理配置爲:
// lb01 [root@lb01 /]# vim /usr/local/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 webpools { #若是就是單個Server,不必設置權重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #熱備機器設置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; proxy_set_header host $host; #在代理向後端服務器發送的http請求頭中加入host字段信息,用於當後端服務器配置有多個虛擬主機時,能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。 } } }
此時,再從新加載Nginx服務,並用curl測試檢查,結果以下:
[root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 www [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 www [root@lb01 /]# curl bbs.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl bbs.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
能夠看到此次訪問的結果和訪問的域名就徹底對應上了,這樣代理多虛擬主機的節點服務器就不會出問題了
修改 nginx.config 記錄日誌
// web01 [root@web01 conf]# vim /usr/local/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"'; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } } // web02 [root@web02 conf]# vim /usr/local/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"'; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } }
完成了反向代理WWW服務後,天然很開心,可是,不久後你用其餘客戶端做爲客戶端測試時,就會發現一個問題,節點服務器對應的WWW虛擬主機的訪問日誌的第一個字段記錄的並非客戶端的IP,而是反向代理服務器的IP,最後一個字段也是「-」!
例如:使用任意windows客戶端計算機( 192.168.103.204 ),訪問已經解析好代理IP的www.yunjisuan.com後,去節點服務器www服務日誌查看,就會發現以下日誌:
[root@web02 logs]# tail -2 /usr/local/nginx/logs/access_www.log 192.168.103.121--[29/Aug/2019:17:29:23 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-" 192.168.103.121--[29/Aug/2019:17:29:33 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"
Web01節點服務器對應的WWW虛擬主機的訪問日誌的第一個字段記錄的並非客戶端的IP而是反向代理服務器自己的IP(192.168.103.121),最後一個字段也是一個「-」,那麼如何解決這個問題?其實很簡單,一樣是增長以下一行參數:
proxy_set_header X-Forwarded-For $remote_addr;
#這是反向代理時,節點服務器獲取用戶真實IP的必要功能配置
解決上述問題的整個Nginx代理配置爲:
//lb01 [root@lb01 /]# vim /usr/local/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 webpools { #若是就是單個Server,不必設置權重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #熱備機器設置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; proxy_set_header host $host; #在代理向後端服務器發送的http請求頭中加入host字段信息,用於當後端服務器配置有多個虛擬主機時,能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。 proxy_set_header X-Forwarded-For $remote_addr; #在代理向後端服務器發送的http請求頭中加入X-Forwarded-For字段信息,用於後端服務器程序,日誌等接收記錄真實用戶的IP,而不是代理服務器的IP } } }
從新加載Nginx反向代理服務:
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
特別注意,雖然反向代理已經配好了,可是節點服務器須要的訪問日誌若是要記錄用戶的真實IP,還必須進行日誌格式配置,這樣才能把代理傳過來的X-Forwarded-For頭信息記錄下來,具體配置爲:
// web01 [root@web01 /]# vim usr/local/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.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } } // web02 [root@web02 /]# vim usr/local/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.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } }
完成Web01,Web02節點服務器的日誌配置後,就能夠檢查了,注意,不要用curl從反向代理上檢查,最好換一個客戶端檢查,這樣才能看到效果。這裏使用Windows客戶端計算機(IP爲192.168.103.204)訪問已經解析好代理IP的www.yunjisuan.com,以下圖所示:
// web01 [root@web01 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 192.168.103.121--[29/Aug/2019:18:02:38 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" 192.168.103.121--[29/Aug/2019:18:02:42 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" // web02 [root@web02 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 192.168.103.121--[29/Aug/2019:18:02:41 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" 192.168.103.121--[29/Aug/2019:18:02:44 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
其中,日誌裏的192.168.103.121爲反向代理的IP,對應Nginx日誌格式裏的$remote_addr變量,而日誌結尾的192.168.103.204對應的時日誌格式裏的「$http_x_forwarded_for」變量,即接收了前面反向代理配置中「proxy_set_header X-Forwarded-For $remote_addr;」參數X-Forwarded-For的IP了。
關於X-Forwarded-For的詳細說明,可見http://en.wikipedia.org/wiki/X-Forwwawrded-For。下圖是反向代理相關重要基礎參數的總結,供同窗們參考。
除了具備多虛擬主機代理以及節點服務器記錄真實用戶IP的功能外,Nginx軟件還提供了至關多的做爲反向代理和後端節點服務器對話的相關控制參數,具體見前面在講解proxy模塊時提供的圖表。
相信同窗們對這些參數有了必定了解了,因爲參數衆多,最好把這些參數放到一個配置文件裏,而後用include方式包含到虛擬主機配置裏,效果以下:
//lb01 # 建立配置文件 [root@lb01 /]# vim /usr/local/nginx/conf/proxy.conf proxy_set_header host $host; proxy_set_header x-forwarded-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; #修改配置 [root@lb01 /]# vim /usr/local/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 webpools { #若是就是單個Server,不必設置權重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #熱備機器設置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; include proxy.conf; } } } # 從新加載 [root@lb01 /]# nginx -s reload
更多Nginx反向代理參數說明:
http://nginx.org/en/docs/http/ngx_http_proxy_module.html
案例背景:
經過Nginx實現動靜分離,即經過Nginx反向代理配置規則實現讓動態資源和靜態資源及其餘業務分別由不一樣的服務器解析,以解決網站性能,安全,用戶體驗等重要問題。
下圖爲企業常見的動靜分離集羣架構圖,此架構圖適合網站前端只使用同一個域名提供服務的場景,例如,用戶訪問的域名是www.yunjisuan.com,而後,當用戶請求www.yunjisuan.com/upload/xx地址時候,代理會分配請求到上傳服務器池處理數據;當用戶請求www.yunjisuan.com/static/xx地址的時候,代理會分配請求到靜態服務器池請求數據;當用戶請求www.yunjisuan.com/xx地址的時候,即不包含上述指定的目錄地址路徑時,代理會分配請求到默認的動態服務器池請求數據(注意:上面的xx表示任意路徑)。
先進行企業案例需求梳理:
瞭解了需求後,就能夠進行upstream模塊服務器池的配置了。
//lb01 #static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80. upstream staticpools { server 192.168.103.123:80 weght=1; } #upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80. upstream uploadpools { server 192.168.103.124:80 weight=1; } #default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80. upstream defaultpools { server 192.168.103.125:80 weight=1; } #提示:須要增長一臺測試Web節點Web03(ip:192.168.103.125),配置與Web01,Web02同樣。
下面利用location或if語句把不一樣的URI(路徑)請求,分給不一樣的服務器池處理,具體配置以下。
方案1:以location方案實現
//lb01 #將符合static的請求交給靜態服務器池static_pools,配置以下: location /static/ { proxy_pass http://staticpools; include proxy.conf; } #將符合upload的請求交給上傳服務器池upload_pools,配置以下: location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } #不符合上述規則的請求,默認所有交給動態服務器池default_pools,配置以下: location / { proxy_pass http://defaultpools; include proxy.conf; }
方案2:以if語句實現。
[root@lb01 /]# vim /usr/local/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; server { listen 80; server_name www.yunjisuan.com; location / { if ($request_uri ~* "^/static/(.*)$") { proxy_pass http://staticpools/$1; } if ($request_uri ~* "^/upload/(.*)$") { proxy_pass http://uploadpools/$1; } proxy_pass http://defaultpools; include proxy.conf; } } }
從新加載配置生效,以下:
[root@lb01 /]# /usr/local/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@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
暫時不要馬上測試成果,爲了實現上述代理的測試,還須要在Web01和Web02上作節點的測試配置,才能更好地展現測試效果。
以Web01做爲static靜態服務,地址端口爲:192.168.103.123:80,須要事先配置一個用於測試靜態的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:
// web01 [root@web01 /]# mkdir -p /usr/local/nginx/html/www/static [root@web01 /]# echo "static_pools www" >> /usr/local/nginx/html/www/static/index.html [root@web01 /]# mkdir -p /usr/local/nginx/html/bbs/static [root@web01 /]# echo "static_pools bbs" >> /usr/local/nginx/html/bbs/static/index.html [root@web01 /]# curl http://www.yunjisuan.com/static/index.html #這裏的www.yunjisuan.com是解析過的Web01的本地IP static_pools www [root@web01 /]# curl http://bbs.yunjisuan.com/static/index.html #這裏的bbs.yunjisuan.com是解析過的Web01的本地IP static_pools bbs #提示:測試的靜態地址爲http://www.yunjisuan.com/static/index.html,注意,是帶static路徑的地址。
以Web02做爲upload上傳服務,地址端口爲:192.168.103.124:80,須要事先配置一個用於測試上傳服務的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:
// web02 [root@web02 ~]# mkdir -p /usr/local/nginx/html/www/upload/ [root@web02 ~]# echo "upload_pools www" >> /usr/local/nginx/html/www/upload/index.html [root@web02 ~]# mkdir -p /usr/local/nginx/html/bbs/upload [root@web02 ~]# echo "upload_pools bbs" >> /usr/local/nginx/html/bbs/upload/index.html [root@web02 ~]# curl http://www.yunjisuan.com/upload/index.html #這裏的www.yunjisuan.com是解析過的Web02的本地IP upload_pools www [root@web02 ~]# curl http://bbs.yunjisuan.com/upload/index.html #這裏的bbs.yunjisuan.com是解析過的Web02的本地IP upload_pools bbs #提示:測試的上傳地址爲http://www.yunjisuan.com/upload/index.html,注意,是帶upload路徑的地址。
在Web03做爲動態服務節點,地址端口爲192.168.103.125:80,一樣須要事先配置一個默認的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:
[root@web03 /]# cd /usr/local/nginx/html/www [root@web03 www]# echo "default_pools" > index.html [root@web03 www]# curl http://www.yunjisuan.com default_pools
以上準備了上臺Web節點服務器,分別加入到了upstream定義的不一樣服務器池,表明三組不一樣的業務集羣組,從本機經過hosts解析各自的域名,而後測試訪問,其地址與實際訪問的內容輸出請對照下表:
節點 | IP及端口 | 測試地址 | 字符串爲表明業務 |
---|---|---|---|
web01 | 192.168.103.123:80 | http://www.yunjisuan.com/static/index.html | static_pools |
web02 | 192.168.103.124:80 | http://www.yunjisuan.com/upload/index.html | upload_pools |
web03 | 192.168.103.125:80 | http://www.yunjisuan.com | default_pools |
使用客戶端計算機訪問測試時,最好選用集羣之外的機器,這裏先在瀏覽器客戶端的hosts文件裏把www.yunjisuan.com解析到Nginx反向代理服務器的IP,而後訪問上述URL,看代理是否是把請求正確地轉發到了指定的服務器上。若是能夠獲得與上表對應的內容,表示配置的Nginx代理分發的徹底正確,由於若是分發請求到錯誤的機器上就沒有對應的URL頁面內容,輸出會是404錯誤。
[root@lb01 /]# curl http://www.yunjisuan.com/static/index.html static_pools www [root@lb01 /]# curl http://www.yunjisuan.com/upload/index.html upload_pools www [root@lb01 /]# curl http://www.yunjisuan.com default_pools
實際配置以下:
// lb01
[root@lb01 /]# vim /usr/local/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; # static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80. upstream staticpools { server 192.168.103.123:80 ; } # upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80. upstream uploadpools { server 192.168.103.124:80 ; } # default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80. upstream defaultpools { server 192.168.103.125:80 ; } server { listen 80; server_name www.yunjisuan.com; location /static/ { proxy_pass http://staticpools; include proxy.conf; } location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } location / { proxy_pass http://defaultpools; include proxy.conf; } } }
在企業中,爲了讓不一樣的客戶端設備用戶訪問有更好的體驗,須要在後端架設不一樣服務器來知足不一樣的客戶端訪問,例如:移動客戶端訪問網站,就須要部署單獨的移動服務器及程序,體驗才能更好,並且移動端還分蘋果,安卓,Ipad等,在傳統的狀況下,通常用下面的辦法解決這個問題。
此解決方案的最大問題就是不一樣客戶端的用戶要記住對應的域名!而絕大多數用戶只會記住www.yunjisuan.com,不會記住wap.yunjisuan.com,這樣一來就會致使用戶體驗不是很好。有沒有辦法讓全部客戶端用戶只訪問一個統一的www.yunjisuan.com這個地址,還能讓不一樣客戶端設備都能有更好的訪問體驗呢?固然有!那就是下面的第7層負載均衡解決方案。
這裏仍是使用static_pools,upload_pools做爲本次實驗的後端服務器池。下面先根據計算機客戶端瀏覽器的不一樣設置對應的匹配規則。(因爲沒有合適的實驗驗證環境,這裏僅做需求實現的細節講解)
//lb01 location / { if ($http_user_agent ~* "MSIE") # 若是請求的瀏覽器爲微軟IE瀏覽器(MSIE),則讓請求由static_pools池處理 { proxy_pass http://staticpools; } if ($http_user_agent ~* "Chrome") # 若是請求的瀏覽器爲谷歌瀏覽器(Chrome),則讓請求由upload_pools池處理 { proxy_pass http://uploadpools; } # 其餘客戶端,由default_pools處理 proxy_pass http://defaultpools; include proxy.conf; }
除了針對瀏覽器外,上述「$http_user_agent」變量也可針對移動端,好比安卓,蘋果,Ipad設備進行匹配,去請求指定的服務器,具體細節配置以下:
//lb01 location / { if ($http_user_agent ~* "android") { proxy_pass http://android_pools; #這裏是android服務器池 } if ($http_user_agent ~* "iphone") { proxy_pass http://iphone_pools; #這裏是iphone服務器池 } proxy_pass http://pc_pools; #這裏是默認的pc服務器池 include extra/proxy.conf; }
192.168.0.110--[28/Jul/2017:02:12:10 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)""-" #PCwindows訪問日誌 192.168.0.106--[28/Jul/2017:02:12:22 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.0 Mobile/14G60 Safari/602.1""-" #蘋果iphone6手機設備訪問的日誌。
除了根據URI路徑及user_agent轉發外,還能夠實現根據文件擴展名進行轉發(這裏僅以細節配置做爲講解內容,如需測試請同窗們自行實驗)
#先看看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; }
可根據擴展名實現資源的動靜分離訪問,如圖片,視頻等請求靜態服務器池,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 }
在開發沒法經過程序實現動靜分離的時候,運維能夠根據資源實體進行動靜分離,而不依賴於開發,具體實現策略是先把後端的服務器分紅不一樣的組。注意,每組服務器的程序都是相同的,由於開發沒有把程序拆開,分組後,在前端代理服務器上經過講解過的路徑,擴展名進行規則匹配,從而實現請求的動靜分離。
淘寶技術團隊開發了一個Tengine(Nginx的分支)模塊Nginx_upstream_check_module,用於提供主動式後端服務器健康檢查。經過它能夠檢測後端realserver的健康狀態,若是後端realserver不可用,則全部的請求就不會轉發到該節點上。
Tengine原生支持這個模塊,而Nginx則須要經過打補丁的方式將該模塊添加到Nginx中。補丁下載地址:https://github.com/yaoweibin/nginx_upstream_check_module。下面介紹如何使用這個模塊。
#系統已經安裝了nginx-1.10.2軟件 [root@lb01 ~]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.10.2 #下載補丁包 [root@lb01 ~]# wget https://codeload.github.com/786744873/nginx_upstream_check_module/zip/master [root@lb01 ~]# unzip master [root@lb01 ~]# ls anaconda-ks.cfg install.log install.log.syslog master nginx-1.10.2.tar.gz nginx_upstream_check_module-master [root@lb01 nginx-1.10.2]# mv ~/nginx_upstream_check_module-master /usr/src/ #由於是對源程序打補丁,因此還須要Nginx源程序 [root@lb01 ~]# cd /usr/src/nginx-1.10.2/ [root@lb01 nginx-1.10.2]# patch -p0 < /usr/src/nginx_upstream_check_module-master/check_1.9.2+.patch patching file src/http/modules/ngx_http_upstream_hash_module.c patching file src/http/modules/ngx_http_upstream_ip_hash_module.c patching file src/http/modules/ngx_http_upstream_least_conn_module.c patching file src/http/ngx_http_upstream_round_robin.c patching file src/http/ngx_http_upstream_round_robin.h #備份源安裝程序 [root@lb01 nginx-1.10.2]# cd /usr/local/ [root@lb01 local]# ls bin etc games include lib lib64 libexec nginx sbin share src [root@lb01 local]# mv nginx{,.ori} [root@lb01 local]# ls bin etc games include lib lib64 libexec nginx.ori sbin share src [root@lb01 local]# cd /usr/src/nginx-1.10.2/ #從新進行編譯,編譯的參數要和之前一致,最後加上 --add-module=/usr/src/nginx_upstream_check_module-master/ [root@lb01 nginx-1.10.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/ [root@lb01 local]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.10.2 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/ #拷貝源配置文件到當前Nginx的安裝目錄下 [root@lb01 local]# pwd /usr/local [root@lb01 local]# cp nginx.ori/conf/nginx.conf nginx/conf/ cp: overwrite `nginx/conf/nginx.conf'? y [root@lb01 local]# cp nginx.ori/conf/proxy.conf nginx/conf/ [root@lb01 local]# /usr/local/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@lb01 local]# vim 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; # static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80. upstream staticpools { server 192.168.103.123:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #對static服務器池開啓健康監測 } # upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80. upstream uploadpools { server 192.168.103.124:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #對static服務器池開啓健康監測 } # default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80. upstream defaultpools { server 192.168.103.125:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #對static服務器池開啓健康監測 } server { listen 80; server_name www.yunjisuan.com; location / { if ($http_user_agent ~* "MSIE") #若是請求的瀏覽器爲微軟IE瀏覽器(MSIE),則讓請求由static_pools池處理 { proxy_pass http://staticpools; } if ($http_user_agent ~* "Chrome") #若是請求的瀏覽器爲谷歌瀏覽器(Chrome),則讓請求由upload_pools池處理 { proxy_pass http://uploadpools; } proxy_pass http://defaultpools; include proxy.conf; } location /status { check_status; #啓動健康檢查模塊 access_log off; #關閉此location的訪問日誌記錄 } } }
[root@lb01 local]# killall nginx [root@lb01 local]# /usr/local/nginx/sbin/nginx [root@lb01 local]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 20908/nginx: master
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
上面配置的意思時,對static_pools這個負載均衡條目中的全部節點,每隔3秒檢測一次,請求2次正常則標記realserver狀態爲up,若是檢測5次都失敗,則標記realserver的狀態爲down,超時時間爲1秒,檢查的協議是HTTP。
詳細用法見官網:http://tengine.taobao.org/document_cn/http_upstream_check_cn.html
關閉任意一個RS節點後(3個Web服務器任選一個關閉nginx服務)
當Nginx接收後端服務器返回proxy_next_upstream參數定義的狀態碼時,會將這個請求轉發給正常工做的後端服務器,例如500,502,503,504,此參數能夠提高用戶的訪問體驗,具體配置以下:
server { listen 80; server_name www.yunjisuan.com; location / { proxy_pass http://static_pools; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; include proxy.conf; } }