上次我們遇到了一個 MySQL 故障的事故,這次我又遇到了另外一個奇葩的問題:
Keepalived 高可用組件的虛擬 IP 持續(xù)漂移,導(dǎo)致 MySQL 主從不斷切換,進(jìn)而導(dǎo)致 MySQL 主從數(shù)據(jù)同步失敗。
雖然沒能重現(xiàn) Keepalived 的這個問題,但是我深入研究了下 Keepalived 的原理以及針對核心配置參數(shù)做了大量實(shí)驗(yàn)。悟空帶著大家一起看下 Keepalived 到底是如何運(yùn)轉(zhuǎn)的,以及為什么它能做到高可用。
原理講解分為上、中、下三篇:
上篇涉及以下知識點(diǎn):
中篇涉及以下知識點(diǎn):
下篇設(shè)計(jì)以下知識點(diǎn):
談到 Keepalived,給人的印象就是用在高可用架構(gòu)中,保證某個服務(wù)不故障,其實(shí)它還有很多其他的功能。Keepalived 是 Linux 系統(tǒng)下的一個比較輕量級的高可用解決方案,這個輕量級是相對于 Heartbeat 等組件的。雖然 Heartbeat 功能完善、專業(yè)性強(qiáng),但是安裝部署就沒有 Keepalived 簡單,Keepalived 只需要一個配置文件即可。企業(yè)中大多選擇 Keepalived 作為高可用組件。
Keepalived 最開始是由 Alexandre Cassen 使用 C 語言編寫的開源軟件項(xiàng)目,項(xiàng)目的目的主要是簡化 LVS 項(xiàng)目的配置并增強(qiáng) LVS 的穩(wěn)定性。簡單來說,Keepalived 就是對 LVS 的擴(kuò)展增強(qiáng)。
LVS(Linux Virtual Server)翻譯過來就是 Linux 虛擬服務(wù)器,由章文嵩博士主導(dǎo)開發(fā)的開源負(fù)載項(xiàng)目,目前 LVS 已經(jīng)被集成到 Linux 內(nèi)核模塊中。
LVS 主要用在負(fù)載均衡方面,比如 Web 客戶端想要訪問后端服務(wù),Web 請求會先經(jīng)過 LVS 調(diào)度器,調(diào)度器根據(jù)預(yù)設(shè)的算法決定如何分發(fā)給后端的所有服務(wù)器。
LVS 的基本原理如下圖所示:
LVS 的核心功能就是提供負(fù)載均衡,負(fù)載均衡技術(shù)有多種:
而效率最高的是基于 IP 地址的調(diào)度方案。其實(shí)就是將請求轉(zhuǎn)發(fā)給對應(yīng)的 IP 地址 + 端口號,它的效率是非常高的,LVS 的 IP 負(fù)載均衡技術(shù)是通過 IPVS 模塊來實(shí)現(xiàn)的,IPVS 是 LVS 集群系統(tǒng)的核心軟件。
LVS 負(fù)載均衡器會虛擬化一個IP(VIP),對于客戶端來說,它事先只知道這個 VIP 的,客戶端就將請求發(fā)送給 VIP,然后 LVS 負(fù)載均衡器會將請求轉(zhuǎn)發(fā)給后端服務(wù)器中的一個,這些服務(wù)器都稱為 Real Server(真實(shí)服務(wù)器)。轉(zhuǎn)發(fā)的規(guī)則是通過設(shè)置 LVS 的負(fù)載均衡算法來的,比如隨機(jī)分配、按照權(quán)重分配等。
后端服務(wù)器的提供的功能要求是一致的,不論轉(zhuǎn)發(fā)到哪臺服務(wù)器,最終得到的結(jié)果是一致的,所以對于客戶端來說,它并不關(guān)心有多少個后端服務(wù)器在提供服務(wù),它只關(guān)心訪問的 VIP 是多少。
那么后端服務(wù)處理完請求后,如何將數(shù)據(jù)返回給客戶端呢?根據(jù) LVS 的不同模式,會選擇不同的方式將數(shù)據(jù)返回給客戶端。LVS 的工作模式有三種:NAT 模式、TUN 模式、DR 模式。這個后面講到路由機(jī)制再來細(xì)說。
Keepalived 為 Linux 系統(tǒng)提供了負(fù)載均衡和高可用能力。負(fù)載均衡的能力來自 Linux 內(nèi)核中的 LVS 項(xiàng)目模塊 IPVS(IP Virtual Server)。
Keepalived 運(yùn)行在 Linux 系統(tǒng)中,它會啟動內(nèi)核中的 LVS 服務(wù)來創(chuàng)建虛擬服務(wù)器。比如我們在兩臺服務(wù)器上都啟動了一個 Keepalived 服務(wù),然后 LVS 會虛擬化出來一個 IP(VIP),但是只有一個 Keepalived 會接管這個 VIP,就是說客戶端的請求只會到 Master Keepalived 節(jié)點(diǎn)上。這樣流量就只會到一臺 keepalived 上了,然后 keepalived 可以配置幾臺真實(shí)的服務(wù) IP 地址和端口,通過負(fù)載調(diào)度算法將流量分?jǐn)偟竭@些服務(wù)上。對于另外一臺 Backup Keepalived 節(jié)點(diǎn),它是待機(jī)狀態(tài),沒有流量接入的。
那么上面的兩個 Keepalived 服務(wù)是如何選出其中一個作為 Master 節(jié)點(diǎn)的呢?
我們一般都是運(yùn)行在兩臺主備服務(wù)器或一主多備的服務(wù)器上。而這多臺服務(wù)器都是遵循 VRRP 的。
VRRP 的全稱為 Virtual Router Redundancy Protoco,虛擬路由冗余協(xié)議。它是一種容錯協(xié)議,為了解決局域網(wǎng)中單點(diǎn)路由故障的問題。比如之前我們都是一個路由器進(jìn)行路由轉(zhuǎn)發(fā),如果這個路由器故障了,那么整個路由轉(zhuǎn)發(fā)的鏈路就斷了,服務(wù)就不可用了。
VRRP 協(xié)議主要的功能:
現(xiàn)在我們配置多臺路由器(一主多備),每臺路由器都有一個自己的 IP 地址,它們組成一個路由器組,其中有一個作為 Master,其他作為 Backup。然后這些路由器會虛擬出單個路由,擁有自己的 IP 地址,也就是 Virtual IP,簡稱 VIP。
客戶端訪問這個虛擬的 IP 地址就可以了,當(dāng)主路由器故障了,備份路由器通過選舉機(jī)制選出一個新的主路由器,繼續(xù)向客戶端提供路由服務(wù),實(shí)現(xiàn)了路由功能的高可用。
路由器開啟 VRRP 功能后,根據(jù)優(yōu)先級配置進(jìn)行選舉,優(yōu)先級高的會成為主(Master)路由器,另外的則會成為備(Backup)路由器。
Master 路由器定期發(fā)送 VRRP 通知報(bào)文給 Backup 路由器,告訴它們我是在正常工作的,你們不用競選新的 Master 路由器。
關(guān)于 Master 和 Backup 通信的原理其實(shí)很簡單,就是一個心跳機(jī)制,不過這個和 Eureka 的心跳機(jī)制不一樣,Eureka 是客戶端定期向 Eureka 注冊中心發(fā)送心跳,而 Keepalived 則是 Master 定期向 Backup 發(fā)送心跳機(jī)制,而 Backup 路由器它有一個定時監(jiān)測通知的任務(wù),如果在這個時間段內(nèi)未收到通知,則認(rèn)為 Mater 故障了,然后通過優(yōu)先級進(jìn)行選舉,選舉出新的 Master 后,就定期發(fā)送 VRRP 通知報(bào)文給 Backup 路由器。(Eureka 心跳機(jī)制:唐太宗把微服務(wù)的“心跳機(jī)制”玩到了極致!)
通過這個 VRRP 協(xié)議,可以提高系統(tǒng)的可用性,避免因單點(diǎn)故障導(dǎo)致的服務(wù)不可用問題,同時在路由器故障時,無需手動修改網(wǎng)絡(luò)連接信息以訪問新的 Master 路由器。如下圖所示,Backup 切換為了 Master。
關(guān)于選舉的配置主要依賴 vrrp_instance 和 vrrp_script 字段。
對于 Keepalived 的選主有三個重要參數(shù):
vrrp_instance VI_1 {
# 節(jié)點(diǎn)為 BACKUP
state BACKUP
# 優(yōu)先級為 100
priority 100
# 不搶占模式
nopreempt
}
當(dāng)一臺設(shè)置為 master,另外一臺設(shè)置為 BACKUP,當(dāng) MASTER 故障后,BACKUP 會成為新的 MASTER,而當(dāng)老的 MASTER 恢復(fù)后,又會搶占成為新的 MASTER,接管 VIP 的流量,導(dǎo)致不必要的主備切換。為了避免這種主備切換,我們可以將兩臺 Keepalived 都設(shè)置為 BACKUP,且高優(yōu)先級的那臺 Keepalived 設(shè)置為不搶占 nopreempt。
而優(yōu)先級 priority 它是可以增減的,通過 vrrp_script 來配置:
vrrp_script restart_mysql {
# 監(jiān)測和重啟 mysql 容器,如果 MySQL 服務(wù)正常或 MySQL 失敗
script '/usr/local/keepalived/restart_mysql.sh'
interval 5
weight -20
}
這個是定時執(zhí)行腳本的配置,script 配置會監(jiān)測 mysql 服務(wù)是否不正常。這是一個自定義的腳本,可以自己寫返回值。這里我寫的邏輯是如果 MySQL 服務(wù)正常則返回 0,不正常則返回 1。
當(dāng)腳本返回 0 時(服務(wù)正常),則增加優(yōu)先級=priority + weight;否則,保持設(shè)置的 priority 值。
切換策略:
當(dāng)腳本返回非 0 時(服務(wù)異常),則優(yōu)先級=priority - |weight|;否則,保持設(shè)置的 priority 值。
切換策略:
注意:增加或減少優(yōu)先級的范圍為 [1,254]。
舉例說明:
兩臺 Keepalived 的 state 都配置成 BACKUP,其中一臺服務(wù)器 node1 的 Keepalived 的優(yōu)先級設(shè)置為 100,不搶占模式,另外一臺 node2 的優(yōu)先級設(shè)置為 90,搶占模式。
node1 節(jié)點(diǎn)配置的優(yōu)先級高,它成為 Master 節(jié)點(diǎn),當(dāng) Master 節(jié)點(diǎn)監(jiān)控的 MySQL 服務(wù)發(fā)生故障后,會降低優(yōu)先級,從 100 降低到 80。另外一臺優(yōu)先級為 90,收到優(yōu)先級比自己低的 ARP 廣播時,就會變成新的 Master 節(jié)點(diǎn)。而 node1 節(jié)點(diǎn)會成為 BACKUP 節(jié)點(diǎn),當(dāng) node1 監(jiān)控到 MySQL 服務(wù)恢復(fù)后,優(yōu)先級變?yōu)榕渲玫?priority 100,但是也不會搶占。
如下圖所示:雖然 node1 上的 keepalived 重啟 mysql 成功了,優(yōu)先級也恢復(fù)成了 100,但是并沒有變?yōu)?master,還是維持 backup 狀態(tài)。
而 node2 還是 master 節(jié)點(diǎn),定時向 node 1 發(fā)送 vrrp 通知,如下圖所示:
如果 node2 的 mysql 宕機(jī)了,那么它的優(yōu)先級會從 90 降低到 70,即使這樣,也不會出現(xiàn)主備切換,因?yàn)槲覀兣渲玫牟呗跃褪?node1 不會搶占。如果要在這種情況下切換到 node1,就只能將 node2 的 keepalived 主動停掉,故障轉(zhuǎn)移中篇會講到。
要理解 Keepalived 的負(fù)載均衡機(jī)制,必須了解 IPVS,也就是 IP Virtual Server,IP 虛擬服務(wù)器。
IPVS 模塊是 Keepalived 引入的一個第三方模塊,目的是解決單 IP 多服務(wù)器的工作環(huán)境,通過 IPVS 可以實(shí)現(xiàn)基于 IP 的負(fù)載均衡集群。IPVS 默認(rèn)包含在 LVS 軟件中,而 LVS 又是包含在 Linux 系統(tǒng)中。所以 Keepalived 在 Linux 系統(tǒng)上可以直接利用 LVS 的功能。LVS 的作用就是虛擬出一個 IP,也就是 VIP,客戶端請求先到達(dá) VIP,然后從服務(wù)器集群中選擇一個服務(wù)器節(jié)點(diǎn),將流量轉(zhuǎn)發(fā)給這個節(jié)點(diǎn),由這個節(jié)點(diǎn)處理請求。
如圖所示:
virtual_server 192.168.56.88 80 {
delay_loop 6
lb_algo rr
lb kind NAT
protocol tcp
# 服務(wù)器 1
real_server 192.168.56.11 80 {
TCP_CHECK {
connect timeout 10
}
# 服務(wù)器 2
real_server 192.168.56.12 80 {
TCP_CHECK {
connect timeout 10
}
# 服務(wù)器 3
real_server 192.168.56.13 80 {
TCP_CHECK {
connect timeout 10
}
配置中有一個字段 lb_algo,這個就是負(fù)載調(diào)度算法,可以配置成 rr、wrr、lc、wlc、sh、dh 等。常用的是 rr 和 wrr。
Keepalived 作為高可用、高性能組件,在集群環(huán)境中用得還是挺多的,所以去理解 Keepalived 的底層原理,也可以學(xué)到很多高可用和負(fù)載均衡的通用原理。
本篇介紹了 Keepalived 的 IPVS 功能,啟動了一個虛擬服務(wù)器,虛擬化了一個 VIP,用來接收客戶端的請求,然后通過負(fù)載調(diào)度算法將流量轉(zhuǎn)發(fā)給真實(shí)服務(wù)器。
Keepalived 一般用在都是一主一備或一主多備的場景,而對于主的選舉是通過配置 state、privority、nopreemt、weight 字段來達(dá)到的。
下篇我們再來看下真實(shí)服務(wù)器處理完請求后,如何將數(shù)據(jù)返回給客戶端,這個涉及到 LVS 的路由規(guī)則。以及監(jiān)控和故障切換也是 Keepalived 的核心功能,這個很有必要深入探索下。
聯(lián)系客服