1. 程式人生 > 實用技巧 >Keepalived nginx HA負載均衡

Keepalived nginx HA負載均衡

一、開始

1.1 keepalived HA模式

keepalived的HA分為搶佔模式和非搶佔模式,搶佔模式即MASTER從故障中恢復後,會將VIP從BACKUP節點中搶佔過來。非搶佔模式即MASTER恢復後不搶佔BACKUP升級為MASTER後的VIP。本例主要介紹搶佔模式。

1.2 方案規劃

virtual_server(vip)

real_server(ip)

MASTER/BACKUP

服務端

192.168.177.100

192.168.177.181

MASTER

192.168.176

192.168.177.100

192.168.177.191

BACKUP

192.168.167

分別在兩臺real_server安裝keepalived和nginx,通過keepalive保證nginx的高可用。請求流程如下:客戶端發起請求到vip,如果master存活,就通過master的nginx負載分發到服務端;如果master節點掛掉,則keepalived會將vip漂移到backup,此時backup的nginx會將請求負載分發到服務端。如果master完成了故障處理,恢復服務,那麼會將vip搶佔回來,而客戶端無需關心具體是那一臺nginx server對請求進行了分發,實現對伺服器的解耦(本例nginx負載均衡策略為最少連線)。

1.3 環境介紹

伺服器版本:CentOS Linux release 7.6.1810 (Core)

keepalived版本:keepalived-1.3.5-16.el7.x86_64

nginx版本:nginx-1.18.0-1.el7.ngx.x86_64

1.4 環境準備

1.4.1 防火牆

防火牆新增arrp組播規則,或關閉防火牆。本例關閉防火牆:

# 檢視防火牆狀態
firewall-cmd --state
# 停止firewall
systemctl stop firewalld.service
# 禁止firewall開機啟動
systemctl disable firewalld.service

1.4.2 關閉selinux

如果沒有關閉可能會導致keepalived.server或nginx.service啟動失敗。將SELINUX= enforcing改為SELINUX=disabled。

vi /etc/sysconfig/selinux

SELINUX=disabled

1.5 安裝Nginx(有網路)

1.5.1 配置yum儲存庫

1>建立檔案
vi /etc/yum.repos.d/nginx.repo
2>插入如下資訊(指定下載地址,本機系統及系統版本)
[nginx]
name=nginx repo  
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

1.5.2 下載安裝

yum install nginx -y

1.5.3 檢視安裝的nginx版本

nginx -v

1.6安裝Keepalived

1.6.1 下載安裝

yum install keepalived -y

1.7.2 啟動並設定開機自啟

systemctl start keepalived.service
systemctl enable keepalived.service

二、修改配置

2.1 keepalived配置

2.11 編輯/etc/keepalived/keepalived.conf配置檔案

1> MASTER(192.168.177.181):

! Configuration File for keepalived

global_defs {
   notification_email {
     # 郵件通知
     root@localhost
   }
   # 指定發件人
   notification_email_from [email protected]
   # 指定smtp伺服器地址
   smtp_server 127.0.0.1
   # 指定smtp連線超時時間
   smtp_connect_timeout 30
   # 此處注意router_id為負載均衡標識,在區域網內應該是唯一的,通常為hostname
   router_id LVS_DEVEL_181
}

# keepalived會定時執行指令碼並對指令碼執行的結果進行分析,動態調整vrrp_instance的優先順序。
# 如果指令碼執行結果為0,並且weight配置的值大於0,則優先順序相應的增加。如果指令碼執行結果非0,
# 並且weight配置的值小於 0,則優先順序相應的減少。其他情況,維持原本配置的優先順序,即配置檔案中priority對應的值。
vrrp_script chk_nginx {
       script "/etc/keepalived/nginx_check.sh"
       # 每2秒檢測一次nginx的執行狀態
       interval 2
       # 失敗一次,將自己的優先順序-20
       weight -20
}

# 虛擬路由的識別符號
vrrp_instance VI_1 {
    # 狀態只有MASTER和BACKUP兩種,並且要大寫,MASTER為工作狀態,BACKUP是備用狀態
    state MASTER
    # 通訊所使用的網路介面,可用ifconfig檢視
    interface ens32
    # 虛擬路由的ID號,是虛擬路由MAC的最後一位地址
    virtual_router_id 51
    # 指定傳送組播資料包的源IP地址。預設是繫結VRRP例項的介面的主IP地址
    mcast_src_ip 192.168.177.181
    # 此節點的優先順序,主節點的優先順序需要比其他節點高
    priority 100
    # 通告的間隔時間
    advert_int 1
    # 認證配置
    authentication {
        # 認證方式
        auth_type PASS
        # 認證密碼
        auth_pass 1111  
    }
# 虛擬IP,兩個節點設定必須一樣。可以設定多個,一行寫一個 
# 虛擬ip地址,可以有多個地址,每個地址佔一行,不需要子網掩碼,同時這個ip 必須與我們在lvs 客戶端設定的vip 相一致!                   
    virtual_ipaddress {
        192.168.177.100
    }
    track_script {
       # nginx存活狀態檢測指令碼
       chk_nginx
    }
}

# 叢集所使用的VIP和埠
virtual_server 192.168.177.100 443 {
    # 健康檢查間隔,單位為秒
    delay_loop 6
    # lvs排程演算法rr|wrr|lc|wlc|lblc|sh|dh
    lb_algo rr
    # 負載均衡轉發規則。一般包括DR,NAT,TUN 3種
    lb_kind NAT
    # 會話保持時間,會話保持,就是把使用者請求轉發給同一個伺服器,不然剛在1上提交完帳號密碼,就跳轉到另一臺伺服器2上了
    persistence_timeout 50
    # 轉發協議,有TCP和UDP兩種,一般用TCP
    protocol TCP
    
    # 真實伺服器,包括IP和埠號
    real_server 192.168.177.181 443 {
    # 預設為1,0為失效
        weight 1
    # 通過tcpcheck判斷RealServer的健康狀態
    TCP_CHECK {
            # 連線超時時間
            connect_timeout 3
            # 重連次數
            nb_get_retry 3
            # 重連間隔時間
            delay_before_retry 3
            # 健康檢查的埠
            connect_port 23
        }
   }
}

2> BACKUP(192.168.177.191)

global_defs {
   # 此處注意router_id為負載均衡標識,在區域網內應該是唯一的
   router_id LVS_DEVEL_191 
}

vrrp_script chk_nginx {
    script "/etc/keepalived/nginx_check.sh"
    interval 2
    weight -20
}

vrrp_instance VI_1 {
    # 與master不同,備份節點為BACKUP
    state BACKUP
    # 根據實際配置 ifconfig檢視
    interface ens33 
    virtual_router_id 51
    # 備,本機ip
    mcast_src_ip 192.168.177.191
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        # VIP 要同master 一致
        192.168.177.100
    }

    track_script {
       chk_nginx
    }
}

virtual_server 192.168.177.100 443 {
    delay_loop 6       
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP
    # 真實伺服器,包括IP和埠號
    real_server 192.168.177.191 443 {
        weight 1
        
    TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 23
        }
   }
}

2.1.2 建立nginx服務檢測指令碼

分別在主、備伺服器/etc/keepalived目錄下建立nginx_check.sh指令碼,併為其新增執行許可權chmod +x /etc/keepalived/nginx_check.sh。用於keepalived定時檢測nginx的服務狀態,如果nginx停止了,會嘗試重新啟動nginx,如果啟動失敗,會將keepalived程序殺死,將vip漂移到備份機器上。

#!/bin/bash
#監測心跳指令碼
#檢視nginx是否啟動,如果沒啟動則啟動,如果啟動不起來,停掉keepalived服務,此時心跳斷掉,服務轉向另一個nginx
counter=$(ps -C nginx --no-heading|wc -l)
echo "${counter}"
if [ "${counter}" = "0" ]; then
    echo "即將啟動nginx"
    service nginx start ##/usr/sbin/nginx #嘗試重新啟動nginx
    sleep 2 #睡眠2秒

    counter=$(ps -C nginx --no-heading|wc -l)
    if [ "${counter}" = "0" ]; then
        service keepalived stop # killall keepalived #啟動失敗,將keepalived服務殺死。將vip漂移到其它備份節點
        echo "nginx啟動失敗,將vip漂移到其它備份節點"
    else
        echo "nginx啟動成功"
    fi
fi

2.1.3 啟動keepalived服務

service keepalived start

檢視keepalived是否啟動成功

ps -ef | grep keepalived

檢視nginx是否啟動成功(如果啟動失敗檢查nginx檢測指令碼,或keepalived配置檔案中的檢測指令碼路徑是否正確,檢查是否多了或少了花括號)

ps -ef | grep nginx

如果看到如下程序資訊,表示keepalived已經啟動成功:

下面用ip add命令檢視vip繫結的情況,如下圖所示:

ip addr

從上圖可以看出,vip地址192.168.177.100繫結在MASTER(192.168.177.181)的ens32網絡卡上。

2.1.4 測試故障轉移

將MASTER(192.168.177.181)上的keepalived停止,檢視vip是否會漂移到192.168.177.191上。

service keepalived stop
ip addr

從上圖可以看出,vip已經成功從181漂移到了191。此時再將181的keepalived服務啟動,由於181是MASTER,所以會將191的VIP搶佔過來。

啟動181的keepalived服務:

service keepalived start

2.2 nginx配置

2.1.1 nginx.conf

使用安裝預設配置,不做任何修改。

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
    
    # 指定自定義配置檔案目錄、名稱(esb.conf生效的原因)
    include /etc/nginx/conf.d/*.conf;
}

2.1.2 my.conf

分別在主、備伺服器/etc/nginx/conf.d目錄下新增my.conf

upstream my10016 {
                least_conn; #最少連線
                server 192.168.177.167:10016; 
                server 192.168.177.176:10016;
    }
    server {
        listen       10016;
        server_name  192.168.177.100;# 監聽ip使用vip
        location / {
            proxy_pass   http://my10016;  # 設定代理
            index  index.html index.htm;
        }
  }

三、負載均衡測試

可自行測試

PostMan呼叫http://192.168.177.100:10016/aaa介面

{"msg":"success","status":"1","server_ip":"192.168.177.176"}

{"msg":"success","status":"1","server_ip":"192.168.177.167"}

四、nginx容錯

4.1 nginx http健康檢查

Nginx健康檢查分為主動健康檢查和被動健康檢查,本例主要介紹被動健康檢查(主動健康檢查參考官方文件:https://docs.nginx.com/nginx/admin-guide/load-balancer/http-health-check/#active-health-checks)。對於被動執行狀況檢查,NGINX會監視事務的發生,並嘗試恢復失敗的連線。如果仍然無法恢復交易,則NGINX將伺服器標記為不可用,並暫時停止向伺服器傳送請求,直到再次將其標記為活動。

upstream my10016 {
    #負載均衡策略,最少連線,預設為輪詢
    #least_conn;
    # 被動健康檢查
    # 如果NGINX無法在30秒內向伺服器傳送請求或沒有收到3次響應,則會將伺服器標記為30秒不可用
    # 如果只有一個單一的伺服器組中,將fail_timeout和max_fails引數被忽略,伺服器永遠不會標記為不可用
    # 意思是在fail_timeout時間內失敗了max_fails次請求後,則認為該上游伺服器不可用,然後將該服務地址踢除掉。fail_timeout時間後會再次將該伺服器加入存活列表,進行重試。
    server 192.168.177.167:10016 fail_timeout=30s max_fails=3;
    server 192.168.177.176:10016 fail_timeout=30s max_fails=3;
}

4.2重試機制

proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;

Default: proxy_next_upstream error timeout;

Context: http, server, location

指定應將請求傳遞到下一個伺服器的情況:

error # 與伺服器建立連線,向其傳遞請求或讀取響應頭時發生錯誤;

timeout # 在與伺服器建立連線,向其傳遞請求或讀取響應頭時發生超時;

invalid_header # 伺服器返回空的或無效的響應;

http_500 # 伺服器返回程式碼為500的響應;

http_502 # 伺服器返回程式碼為502的響應;

http_503 # 伺服器返回程式碼為503的響應;

http_504 # 伺服器返回程式碼504的響應;

http_403 # 伺服器返回程式碼為403的響應;

http_404 # 伺服器返回程式碼為404的響應;

http_429 # 伺服器返回程式碼為429的響應(1.11.13);

non_idempotent # 通常,請求與 非冪等 方法(POST,LOCK,PATCH)不傳遞到請求是否已被髮送到上游伺服器(1.9.13)的下一個伺服器; 啟用此選項顯式允許重試此類請求;

off # 禁用將請求傳遞給下一個伺服器。

proxy_next_upsstream_tries 0表示不限次數

完整示例如下:

upstream my10016 {
    #負載均衡策略,最少連線,預設為輪詢
    #least_conn;
    # 被動健康檢查
    # 如果NGINX無法在30秒內向伺服器傳送請求或沒有收到3次響應,則會將伺服器標記為30秒不可用
    # 如果只有一個單一的伺服器組中,將fail_timeout和max_fails引數被忽略,伺服器永遠不會標記為不可用
    # 意思是在fail_timeout時間內失敗了max_fails次請求後,則認為該上游伺服器不可用,然後將該服務地址踢除掉。fail_timeout時間後會再次將該伺服器加入存活列表,進行重試。
    server 192.168.177.167:10016 fail_timeout=30s max_fails=3;
    server 192.168.177.176:10016 fail_timeout=30s max_fails=3;
}

server {
    listen       10016;

# 監聽vips
    server_name  192.168.177.100;
    location / {
       # 定義了什麼情況下進行重試,此處error,timeout,http_500
       # non_idempotent 允許非冪等請求重試
       # post, lock, patch 這種會對伺服器造成不冪等的方法,預設是不進行重試的,如果一定要進行重試,則要加上這個配置
       proxy_next_upstream error timeout http_500 non_idempotent;
       # 讀取超時時間,預設值60s,此處10s
       # proxy_read_timeout 10s;
       # 連線超時時間
       proxy_connect_timeout 3s;
       # 6s後nginx 重試
       proxy_next_upstream_timeout 6s;
       # 重試次數,注意:此機制可能會導致資料重複插入的情況
       # 參考:https://www.cnblogs.com/lc0605/p/10444086.html
        proxy_next_upstream_tries 3;
        proxy_pass   http://my10016;  # 設定代理
        ndex  index.html index.htm;
    }
}

五、參考文章

5.1 Keepalived系列—配置檔案keepalived.conf詳解

5.2 Keepalived+Nginx實現高可用(HA)

5.3Nginx 失敗重試機制