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; } }