Nginx集羣(負載均衡)

Nginx負載均衡

1、集羣介紹

一、傳統web訪問模型

傳統WEB模型

(1)傳統web訪問模型完成一次請求的步驟

1)用戶發起請求
2)服務器接受請求
3)服務器處理請求(壓力最大)
4)服務器響應請求php

(2)傳統模型缺點

單點故障;
單臺服務器資源有限(客戶端則是無限的);
單臺服務器處理耗時長(客戶等待時間過長);html

(3)傳統模型優化——單點故障解決方案

  • 優化方案一:部署一臺備份服務器,宕機直接切換
    該方案能夠有效解決服務器故障致使的單點故障,但且服務器利用率低、成本高,切換不及時,且沒法解決服務器業務壓力問題。
  • 優化方案二:部署多臺服務器,根據DNS的輪詢解析機制去實現用戶分發
    優點是用戶處理速度獲得了提高,可是當其中一臺故障,dns並不會知道它故障了,依然將請求分給這個服務器,致使一部分用戶訪問不了業務。

二、並行處理解決方案

1)DNS輪詢解析方案
2)多機陣列——集羣模式linux

陣列集羣

  圖中,前面兩臺服務器負責接受請求和分發請求,它本身並不處理請求,將請求分發給後面的業務服務器來處理。業務服務器處理完請求後,將請求發還給分發器,再由分發器將請求發送給客戶,所以分發器還承擔了響應請求的任務。
  因而可知以前傳統模型中服務器端須要承擔的服務器接收請求和響應請求都交給分發器處理了,而業務壓力最大的處理請求則交給業務服務器完成。
  分發器和dns雖然都是進行了分發的工做,但不一樣點在於分發器是本身部署的服務器,而DNS都是使用的運營商的,所以能夠調整分發器的邏輯判斷規則。nginx

三、集羣

  • 計算機集羣簡稱集羣,是一種計算機系統, 它經過一組鬆散集成的計算機軟件或硬件鏈接起來高度緊密地協做完成計算工做。在某種意義上,他們能夠被看做是一臺計算機。 (百度解釋)
  • 將多個物理機器組成一個邏輯計算機,實現負載均衡和容錯。

組成要素:
  1)VIP: 給分發器的一個虛IP
  2)分發器:nginx
  3)數據服務器:web服務器web

四、Nginx集羣原理

  在Nginx集羣中Nginx扮演的角色是:分發器。
  任務:接受請求、分發請求、響應請求。
  功能模塊:
    1)ngx_http_upstream_module:基於應用層(七層)分發模塊
    2)ngx_stream_core_module:基於傳輸層(四層)分發模塊(1.9開始提供該功能)算法

(1)Nginx集羣的實質

  Nginx集羣實際上是:虛擬主機+反向代理+upstream分發模塊組成的。
  虛擬主機:負責接受和響應請求。
  反向代理:帶領用戶去數據服務器拿數據。
  upstream:告訴nginx去哪一個數據服務器拿數據。chrome

(2)數據走向(請求處理流程)

  1)虛擬主機接受用戶請求
  2)虛擬主機去找反向代理(問反向代理去哪拿數據)
  3)反向代理讓去找upstream
  4)upstream告訴一個數據服務器IP
  5)Nginx去找數據服務器,併發起用戶的請求
  6)數據服務器接受請求並處理請求
  7)數據服務器響應請求給Nginx
  8)Nginx響應請求給用戶數據庫

2、使用Nginx分發器構建一個WEB集羣

一、環境準備

  實驗機 : Vmware 虛擬機 2核4G
  網卡:橋接
  系統:centos7.5
  防火牆:關閉
  Selinux:關閉
  網段:192.168.31.0/24
  準備四臺實驗機:都安裝nginx服務,兩臺看成分發器,兩臺看成web服務器。apache

主機名 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

二、配置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

三、配置分發器(輪詢方式分發)

# 清除空行和註釋項
$ 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;
        }
    }
}

四、集羣分發測試(默認輪詢)

  客戶端訪問分發器地址,默認按照輪詢的方式來進行分發。vim

[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

3、Nginx分發算法

  集羣分發算法:如何將用戶請求按照必定的規律分發給業務服務器。主要分爲Nginx集羣默認算法和基於請求頭分發算法。

一、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定向到同一個後端服務 ,後端服務器爲緩存時比較有效。

二、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機器。因此這臺機器壓力會最輕。

三、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

4、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     # 語言

一、基於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

二、基於開發語言分發

  這種分發方式適用於混合開發的網站,某些大型網站既有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

三、基於瀏覽器的分發

  這種基於瀏覽器的分發,常應用於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.

四、基於源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;
    }
}

5、算法特性(應用場景)總結

相關文章
相關標籤/搜索