一、集群介紹
1、傳統web訪問模型
(1)傳統web訪問模型完成一次請求的步驟
1)用戶發起請求
2)服務器接受請求
3)服務器處理請求(壓力最大)
4)服務器響應請求
(2)傳統模型缺點
單點故障;
單台服務器資源有限(客戶端則是無限的);
單台服務器處理耗時長(客戶等待時間過長);
(3)傳統模型優化——單點故障解決方案
- 優化方案一:部署一台備份服務器,宕機直接切換
該方案可以有效解決服務器故障導致的單點故障,但且服務器利用率低、成本高,切換不及時,且無法解決服務器業務壓力問題。 - 優化方案二:部署多台服務器,根據DNS的輪詢解析機制去實現用戶分發
優勢是用戶處理速度得到了提升,但是當其中一台故障,dns並不會知道它故障了,依然將請求分給這個服務器,導致一部分用戶訪問不了業務。
2、並行處理解決方案
1)DNS輪詢解析方案
2)多機陣列——集群模式
圖中,前面兩台服務器負責接受請求和分發請求,它自己並不處理請求,將請求分發給后面的業務服務器來處理。業務服務器處理完請求后,將請求發還給分發器,再由分發器將請求發送給客戶,因此分發器還承擔了響應請求的任務。
由此可見之前傳統模型中服務器端需要承擔的服務器接收請求和響應請求都交給分發器處理了,而業務壓力最大的處理請求則交給業務服務器完成。
分發器和dns雖然都是進行了分發的工作,但不同點在於分發器是自己部署的服務器,而DNS都是使用的運營商的,因此可以調整分發器的邏輯判斷規則。
3、集群
- 計算機集群簡稱集群,是一種計算機系統, 它通過一組松散集成的計算機軟件或硬件連接起來高度緊密地協作完成計算工作。在某種意義上,他們可以被看作是一台計算機。 (百度解釋)
- 將多個物理機器組成一個邏輯計算機,實現負載均衡和容錯。
組成要素:
1)VIP: 給分發器的一個虛IP
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 虛擬機 2核4G
網卡:橋接
系統:centos7.5
防火牆:關閉
Selinux:關閉
網段:192.168.31.0/24
准備四台實驗機:都安裝nginx服務,兩台當作分發器,兩台當作web服務器。
主機名 | IP | 角色 |
---|---|---|
Master.ayitula.com | 192.168.31.40 | 主分發器 |
Backup.ayitula.com | 192.168.31.41 | 備分發器 |
Web01.ayitula.com | 192.168.31.42 | 數據服務器1 |
Web02.ayitula.com | 192.168.31.43 | 數據服務器2 |
2、配置web業務機器
(1)nginx安裝腳本
#!/bin/bash
nginx_pkg='nginx-1.5.1.tar.gz'
nginx_prefix=/usr/local/nginx
html=/var/nginx
log=/var/log/nginx
check13 () {
[ $UID -ne 0 ] && echo "need to be root to that" && exit 1
[ ! -f $nginx_pkg ] && echo "not found source packager" && exit 1
[ ! -d $html ] && mkdir -p $html
[ ! -d $log ] && mkdir -p $log
}
nginx_install () {
source_pkg=`echo $nginx_pkg|awk -F ".tar" '{print $1}'`
[ -d /usr/src/$source_pkg ]&&rm -rf /usr/src/$source_pkg
tar xf $nginx_pkg -C /usr/src
cp nginxd /usr/src/$source_pkg
if [ $? -eq 0 ];then
cd /usr/src/$source_pkg
if [ $? -eq 0 ];then
yum -y install gcc-* pcre pcre-devel zlib zlib-devel openssl-* &> /dev/null
[ $? -ne 0 ]&&"YUM set error" && exit 1
./configure --prefix=$nginx_prefix
if [ $? -eq 0 ];then
make
if [ $? -eq 0 ];then
make install
if [ $? -eq 0 ];then
ln -s -f $nginx_prefix/conf/nginx.conf /etc/
ln -s -f $nginx_prefix/logs/ $log/logs
ln -s -f $nginx_prefix/html $html/html
ln -s -f $nginx_prefix/sbin/ /usr/sbin/
cp nginxd /etc/init.d/nginx;chmod 755 /etc/init.d/nginx
else
exit 1
fi
else
exit 1
fi
else
exit 1
fi
else
exit 1
fi
else
exit 1
fi
[ $? -eq 0 ]&&clear||exit
echo -e "\n\033[32m Nginx Install Success: \033[0m"
echo -e "\n"
echo -e "\tNginx_conf: /etc/nginx.conf"
echo -e "\tNginx_html: $html/html"
echo -e "\tNginx_access_log: $log/logs/access.log"
echo -e "\tNginx_error_log: $log/logs/error.log\n\n\n\n"
read -n1 -p "press any key and exit...."
echo
}
check13
nginx_install
(2)配置web服務器操作
[root@web02 ~]# sh nginx_install # 腳本安裝nginx
[root@web02 ~]# echo web02 > /usr/local/nginx/html/index.html # 寫入頁面
[root@web02 ~]# yum -y install elinks &>/dev/null # 安裝文本瀏覽器
[root@web02 ~]# /usr/local/nginx/sbin/nginx # 啟動nginx
[root@web02 ~]# elinks http://localhost -dump
web02
3、配置分發器(輪詢方式分發)
# 清除空行和注釋項
$ sed -i '/#/d' nginx.conf
$ sed -i '/^$/d' 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.31.42;
server 192.168.31.43;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web; # 去找反向代理
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
4、集群分發測試(默認輪詢)
客戶端訪問分發器地址,默認按照輪詢的方式來進行分發。
[root@web02 ~]# elinks http://192.168.31.40 -dump
web01
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web01
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
三、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、Nginx業務服務器狀態
每個設備的狀態設置參數:
- 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.ayitula.com | 192.168.31.40 | 主分發器 | centos7.5 | 2核4G |
Backup.ayitula.com | 192.168.31.41 | 備分發器 | centos7.5 | 2核4G |
Web01.ayitula.com | 192.168.31.42 | 數據服務器1 | centos7.5 | 2核4G |
Web02.ayitula.com | 192.168.31.43 | 數據服務器2 | centos7.5 | 2核4G |
(1)輪詢算法分發
upstream web {
server 192.168.31.42;
server 192.168.31.43;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
}
}
前面已經測試驗證了輪詢算法分發。配置backup參數如下所示:
upstream web {
server 192.168.31.42 weight=1;
server 192.168.31.43 weight=1 backup;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
}
}
關停第一個節點情況,訪問嘗試:
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
(2)基於權重的分發
upstream web {
# 設置權重比例1:2
server 192.168.31.42 weight=1;
server 192.168.31.43 weight=2;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
}
}
訪問測試驗證:
[root@web02 ~]# elinks http://192.168.31.40 -dump
web01
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web01
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
[root@web02 ~]# elinks http://192.168.31.40 -dump
web02
通過權重比例的分配,可以讓性能更強的服務器承擔處理更多的請求。
(3)基於ip_hash分發
ip_hash算法能夠保證來自同樣源地址的請求都分發到同一台主機。
需要注意:ip_hash算法不支持backup、weight設置。默認權重為1。
upstream web {
ip_hash; # 指定ip_hash即可,默認weight權重比例1: 1
server 192.168.31.42;
server 192.168.31.43;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
}
}
訪問測試驗證:
# 源ip固定
[root@web01 ~]# elinks http://192.168.31.40 -dump
web02
[root@web01 ~]# elinks http://192.168.31.40 -dump
web02
[root@web01 ~]# elinks http://192.168.31.40 -dump
web02
MacBook-Pro:~ hqs$ elinks http://192.168.31.40 -dump
web01
MacBook-Pro:~ hqs$ elinks http://192.168.31.40 -dump
web01
MacBook-Pro:~ hqs$ elinks http://192.168.31.40 -dump
web01
四、Nginx基於請求頭的分發
前面的分發方式都是基於一個集群分發的,而基於請求頭分發一般都是用於多集群分發的。
瀏覽器開發者工具network工具下,獲取請求的請求頭信息如下所示:
Request URL: http://192.168.31.43/ # 請求的URL
Request Method: GET # 請求的方法
Status Code: 200 OK
Remote Address: 192.168.31.43: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.31.42;
server 192.168.31.52;
}
upstream web2 { # 名為web2的反向代理群組
server 192.168.31.43;
server 192.168.31.53;
}
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;
}
}
}
基於域名的分發測試:
[root@web02 ~]# elinks http://www.web1.com -dump
web01
[root@web02 ~]# elinks http://www.web1.com -dump
web01
[root@web02 ~]# elinks http://www.web1.com -dump
web01
[root@web02 ~]# elinks http://www.web2.com -dump
web02
[root@web02 ~]# elinks http://www.web2.com -dump
web02
[root@web02 ~]# elinks http://www.web2.com -dump
web02
2、基於開發語言分發
這種分發方式適用於混合開發的網站,某些大型網站既有php也有jsp,就可以基於開發語言分發。
# 192.168.31.40分發器上nginx配置
http {
upstream php {
server 192.168.31.42;
}
upstream html {
server 192.168.31.43;
}
server {
location ~* \.php$ { # 以php結尾的
proxy_pass http://php;
}
location ~* \.html$ { # 以html結尾的
proxy_pass http://html;
}
}
}
測試驗證:
# 安裝php環境
$ yum install httpd php # 安裝apache和php
# 啟動apache,自帶php
$ systemctl start httpd
# 編寫php文件
$ echo "<?php phpinfo(); ?>" > /var/www/html/index.php
# 訪問192.168.31.40/index.php 可以看到php-info信息頁面
# 訪問192.168.31.40/index.html 可以看到web02
3、基於瀏覽器的分發
這種基於瀏覽器的分發,常應用於PC端和移動端區分或瀏覽器適配。
(1)由於沒有第三個機器,在42這台業務服務器上,啟動一個虛擬主機。
$ vim /usr/local/nginx/conf/nginx.conf
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
}
}
}
$ mkdir /usr/local/nginx/web3
$ echo web03 > /usr/local/nginx/web3/index.html
$ /user/local/nginx/sbin/nginx
(2)基於瀏覽器分發的分發器配置
upstream elinks { server 192.168.31.42; }
upstream chrome { server 192.168.31.43; }
upstream any { server 192.168.31.42: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;
}
}
}
(3)訪問測試
任何機器訪問,只要是使用elinks訪問的都將訪問web01;只要使用chrome瀏覽器訪問都將訪問web02;而使用firefox或者safari則將訪問web03.
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地址。
(2)基於源IP分發配置
upstream bj.server {
server 192.168.31.42; # web01
}
upstream sh.server {
server 192.168.31.43; # web02
}
upstream default.server {
server 192.168.31.42:81; # web03
}
geo $geo { # IP庫
default default;
192.168.31.241/32 bj; # 北京
192.168.31.242/32 sh; # 上海
}
server {
listen 80;
server_name www.web1.com;
location / {
proxy_pass http://$geo.server$request_uri;
}
}