文章目錄
前言
利用 Nginx 的負載均衡和反向代理,我們可以實現後臺應用的高可用。這時候的用戶請求是先通過 nginx, 然後在訪問我們的應用,如果 nginx 掛掉了,那我們所有的應用都無法訪問了。所以我們必須實現 Nginx 的高可用,達到一臺 Nginx 宕機,另一臺備機自動接管服務的效果。
本文沒有直接使用 nginx ,而是使用了 OpenResty 。其實效果是一樣的。 OpenResty 是一個基於 Nginx 與 Lua 的高性能 Web 平臺。
Keepalived 介紹
Keepalived是一個基於VRRP協議來實現的服務高可用方案,可以利用其來避免IP單點故障,類似的工具還有heartbeat、corosync、pacemaker。但是它一般不會單獨出現,而是與其它負載均衡技術(如lvs、haproxy、nginx)一起工作來達到集羣的高可用。
VRRP協議
VRRP全稱 Virtual Router Redundancy Protocol,即 虛擬路由冗餘協議。可以認爲它是實現路由器高可用的容錯協議,即將N臺提供相同功能的路由器組成一個路由器組(Router Group),這個組裏面有一個master和多個backup,但在外界看來就像一臺一樣,構成虛擬路由器,擁有一個虛擬IP(vip,也就是路由器所在局域網內其他機器的默認路由),佔有這個IP的master實際負責ARP相應和轉發IP數據包,組中的其它路由器作爲備份的角色處於待命狀態。master會發組播消息,當backup在超時時間內收不到vrrp包時就認爲master宕掉了,這時就需要根據VRRP的優先級來選舉一個backup當master,保證路由器的高可用。
在VRRP協議實現裏,虛擬路由器使用 00-00-5E-00-01-XX 作爲虛擬MAC地址,XX就是唯一的 VRID (Virtual Router IDentifier),這個地址同一時間只有一個物理路由器佔用。在虛擬路由器裏面的物理路由器組裏面通過多播IP地址 224.0.0.18 來定時發送通告消息。每個Router都有一個 1-255 之間的優先級別,級別最高的(highest priority)將成爲主控(master)路由器。通過降低master的優先權可以讓處於backup狀態的路由器搶佔(pro-empt)主路由器的狀態,兩個backup優先級相同的IP地址較大者爲master,接管虛擬IP。
VRRP協議 + nginx
keepalived可以認爲是VRRP協議在Linux上的實現,主要有三個模塊,分別是core、check和vrrp。core模塊爲keepalived的核心,負責主進程的啓動、維護以及全局配置文件的加載和解析。check負責健康檢查,包括常見的各種檢查方式。vrrp模塊是來實現VRRP協議的。
Keepalived 實現 OpenResty 的高可用
準備
筆者準備了二臺服務器,其 ip 地址爲:
192.168.56.101 worker-01 worker-01.joyxj.com
192.168.56.102 worker-02 worker-02.joyxj.com
系統爲 Centos 7。
我們需要在這二臺服務器上 安裝 OpenResty 和 Keepalived 。其中 192.168.56.101 爲 主機,192.168.56.102 爲備機。
OpenResty 安裝
可以參考 OpenResty 快速入門。
其安裝後的目錄在 /usr/local/openresty
, nginx 目錄在 /usr/local/openresty/nginx
。
Keepliaved 安裝
直接使用 yum 進行安裝
yum -y install kernel kernel-devel* popt popt-devel libssl-dev libnl libnl-devel openssl openssl-* ipvsadm libnfnetlink-devel
yum install -y keepalived
安裝後使用 keepalived -v
查看版本,會輸出以下信息則表示安裝成功。
Keepalived v1.3.5 (03/19,2017), git commit v1.3.5-6-g6fa32f2
Copyright(C) 2001-2017 Alexandre Cassen, <[email protected]>
監控腳本
需要一個腳本,用於監測 Nginx 是否運行,如果 nginx 已經宕機,需要把相應機器的 Keepalived 已關掉,才能實現虛 IP 的飄移。如果不關掉 Keepalived,是不會進行虛 IP 的飄移。
vim /etc/keepalived/check_nginx.sh
#!/bin/bash
# curl -IL http://localhost/member/login.htm
# curl --data "memberName=fengkan&password=22" http://localhost/member/login.htm
count=0
for (( k=0; k<2; k++ ))
do
# 通過 curl 的方式看可否可以訪問 Nginx 的首頁
check_code=$( curl --connect-timeout 3 -sL -w "%{http_code}\\n" http://localhost/index.html -o /dev/null )
if [ "$check_code" != "200" ]; then
count=$(expr $count + 1)
sleep 3
continue
else
count=0
break
fi
done
if [ "$count" != "0" ]; then
/etc/init.d/keepalived stop
exit 1
else
exit 0
fi
Keepalived 配置文件 keepalived.conf
我們需要對 /etc/keepalived/keepalived.conf
做一些修改。
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict 需要註釋掉,否則會無法 ping 通虛 IP。
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script chk_nginx {
# script "killall -0 nginx"
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -5
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface enp0s8 #使用的網卡,這個要和 IP 相對應的網卡一致
virtual_router_id 51
priority 101
advert_int 1
mcast_src_ip 192.168.56.101 # ip
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.56.106 # 虛擬出來的 IP
}
track_script {
chk_nginx
}
}
... 省略其它默認的配置 ...
在另外一臺備機上,只需要改變 state MASTER -> state BACKUP,priority 101 -> priority 100,mcast_src_ip 192.168.56.101 -> mcast_src_ip 192.168.56.102 即可。
啓動
分別在二臺機器上啓動 Nginx 和 Keepalived。
/usr/local/openresty/nginx/sbin/nginx
systemctrl start keepalived
可以通過 /var/log/message
查看日誌。
或者通過 ps
命令查看進程查看 nginx 和 keepalived 是否已經啓動。
ps -ef | grep nginx
ps -ef | grep keepalived
root 6973 1 0 15:22 ? 00:00:00 /usr/sbin/keepalived -D
root 6974 6973 0 15:22 ? 00:00:01 /usr/sbin/keepalived -D
root 6975 6973 0 15:22 ? 00:00:01 /usr/sbin/keepalived -D
root 23980 6975 0 16:22 ? 00:00:00 /usr/sbin/keepalived -D
root 23981 23980 0 16:22 ? 00:00:00 /bin/bash /etc/keepalived/check_nginx.sh
root 23987 3587 0 16:22 pts/0 00:00:00 grep --color=auto keepalived
使用 ip a
命令可以查看 ip 情況。
ip a
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:71:46:c1 brd ff:ff:ff:ff:ff:ff
inet 192.168.56.101/24 brd 192.168.56.255 scope global noprefixroute enp0s8
valid_lft forever preferred_lft forever
inet 192.168.56.106/32 scope global enp0s8
valid_lft forever preferred_lft forever
inet6 fe80::23e9:cd08:cf12:aa6c/64 scope link tentative noprefixroute dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::3725:99a9:e2e2:b667/64 scope link noprefixroute
valid_lft forever preferred_lft forever
從中,可以看到已經多了一個 IP 192.168.56.106
。這個 IP 就是 keepalived 虛擬出來的,通過在 keepalived.conf
文件中配置。
高可用測試
爲了方面測試,我們對 nginx 的首頁進行一些修改,增加一些標識。
直接通過服務器的 IP 進行訪問。
curl http://192.168.56.101
... 省略 ...
<h1>Welcome to OpenResty! worker-01</h1>
... 省略 ...
curl http://192.168.56.102
... 省略 ...
<h1>Welcome to OpenResty! worker-02</h1>
... 省略 ...
其中 worker-01 和 worker-02 是筆者加的標識,分別標識這二臺服務器。其它的輸出內容省略。
下面我們通過虛擬出來的 IP 192.168.56.106
進行訪問。
curl http://192.168.56.106
... 省略 ...
<h1>Welcome to OpenResty! worker-01</h1>
... 省略 ...
我們可以看到,由於 192.168.56.101
這臺服務器被我們設置爲 master ,所以 192.168.56.106
這個虛擬 IP 會漂移到 192.168.56.101
這臺機器上。現在我們把 192.168.56.101
這臺機器的 nginx 停掉,由於我們有一個監控腳本,Nginx 停掉後, Keepalived 也會被停掉。
# 停掉 nginx
/usr/local/openresty/nginx/sbin/nginx -s stop
重新訪問 虛擬 IP。
curl http://192.168.56.106
... 省略 ...
<h1>Welcome to OpenResty! worker-02</h1>
... 省略 ...
此時,已經訪問 192.168.56.102
這臺服務器,實現了切換。
可以通過 ip a
命令查看 ip 信息,發現 192.168.56.106
這個 IP 已經在 192.168.56.102
這臺服務器上了。
ip a
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:72:75:f8 brd ff:ff:ff:ff:ff:ff
inet 192.168.56.102/24 brd 192.168.56.255 scope global noprefixroute enp0s8
valid_lft forever preferred_lft forever
inet 192.168.56.106/32 scope global enp0s8
valid_lft forever preferred_lft forever
inet6 fe80::23e9:cd08:cf12:aa6c/64 scope link noprefixroute
valid_lft forever preferred_lft forever
這樣,我們就實現了 OpenResty 的高可用。