Linux Keepalived配置虛擬IP實(shí)現(xiàn)故障轉(zhuǎn)移的全過程
引言
在現(xiàn)代分布式系統(tǒng)架構(gòu)中,高可用性(High Availability, HA)是保障服務(wù)持續(xù)在線、抵御單點(diǎn)故障的核心能力。無論是電商平臺、金融交易系統(tǒng),還是企業(yè)內(nèi)部的關(guān)鍵業(yè)務(wù)應(yīng)用,一旦服務(wù)中斷,輕則影響用戶體驗(yàn),重則造成經(jīng)濟(jì)損失甚至法律風(fēng)險(xiǎn)。因此,構(gòu)建具備自動(dòng)故障轉(zhuǎn)移能力的系統(tǒng)架構(gòu),已成為每一位后端工程師和運(yùn)維人員的必修課。
在 Linux 環(huán)境下,Keepalived 是實(shí)現(xiàn)虛擬 IP(Virtual IP, VIP)漂移、完成主備切換的經(jīng)典開源工具。它基于 VRRP 協(xié)議(Virtual Router Redundancy Protocol),通過心跳檢測機(jī)制,在主節(jié)點(diǎn)宕機(jī)時(shí),自動(dòng)將 VIP 遷移到備用節(jié)點(diǎn),從而實(shí)現(xiàn)“無縫”故障轉(zhuǎn)移。
本文將從零開始,帶你一步步配置 Keepalived,結(jié)合 Java 應(yīng)用演示真實(shí)場景下的高可用部署,并深入剖析其工作原理、常見問題及優(yōu)化策略。無論你是剛接觸運(yùn)維的新手,還是希望提升系統(tǒng)穩(wěn)定性的資深開發(fā)者,都能從中獲得實(shí)用價(jià)值。
什么是 Keepalived?
Keepalived 最初設(shè)計(jì)用于 LVS(Linux Virtual Server)負(fù)載均衡器的高可用方案,但因其輕量、高效、配置簡單,迅速被廣泛應(yīng)用于各類需要 VIP 漂移的場景,如數(shù)據(jù)庫主從切換、Nginx 高可用、自定義服務(wù)冗余等。
核心特性:
- 基于 VRRP 協(xié)議實(shí)現(xiàn)主備選舉與 VIP 切換
- 支持多播/單播通信模式
- 可自定義健康檢查腳本(check script)
- 支持權(quán)重動(dòng)態(tài)調(diào)整,實(shí)現(xiàn)“搶占”或“非搶占”模式
- 輕量級守護(hù)進(jìn)程,資源占用低
VRRP 協(xié)議小科普:
VRRP 是一種容錯(cuò)協(xié)議,允許多臺路由器組成一個(gè)“虛擬路由器”,對外表現(xiàn)為一個(gè)統(tǒng)一的網(wǎng)關(guān) IP(即 VIP)。當(dāng)主路由器故障,備份路由器自動(dòng)接管 VIP,繼續(xù)提供服務(wù)。Keepalived 將這一思想擴(kuò)展到任意 TCP/IP 服務(wù)上。
實(shí)驗(yàn)環(huán)境準(zhǔn)備
為了便于演示,我們搭建一個(gè)最小化的雙節(jié)點(diǎn)環(huán)境:
| 節(jié)點(diǎn)角色 | 主機(jī)名 | IP 地址 | 操作系統(tǒng) |
|---|---|---|---|
| Master | node-master | 192.168.1.100 | Ubuntu 22.04 LTS |
| Backup | node-backup | 192.168.1.101 | Ubuntu 22.04 LTS |
虛擬 IP(VIP):192.168.1.200
注意:兩臺機(jī)器需在同一局域網(wǎng)內(nèi),且能互相 ping 通。防火墻需放行 VRRP 協(xié)議(協(xié)議號 112)或關(guān)閉防火墻進(jìn)行測試。
安裝 Keepalived
在兩臺機(jī)器上分別執(zhí)行以下命令安裝 Keepalived:
sudo apt update sudo apt install -y keepalived
安裝完成后,配置文件位于 /etc/keepalived/keepalived.conf。默認(rèn)可能不存在,需手動(dòng)創(chuàng)建。
配置 Keepalived(Master 節(jié)點(diǎn))
編輯 Master 節(jié)點(diǎn)的配置文件:
sudo vim /etc/keepalived/keepalived.conf
內(nèi)容如下:
vrrp_instance VI_1 {
state MASTER # 角色:主節(jié)點(diǎn)
interface eth0 # 綁定網(wǎng)卡,根據(jù)實(shí)際修改(可用 ip a 查看)
virtual_router_id 51 # 虛擬路由ID,主備必須一致
priority 100 # 優(yōu)先級,數(shù)值越大越優(yōu)先成為主節(jié)點(diǎn)
advert_int 1 # 心跳檢測間隔(秒)
authentication { # 認(rèn)證配置,主備需一致
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.1.200/24 dev eth0 # 虛擬IP及其子網(wǎng)掩碼、綁定網(wǎng)卡
}
}
提示:interface 需替換為你機(jī)器的實(shí)際網(wǎng)卡名稱,如 ens33、enp0s3 等。
配置 Keepalived(Backup 節(jié)點(diǎn))
在 Backup 節(jié)點(diǎn)上創(chuàng)建相同的配置文件,僅修改三處:
vrrp_instance VI_1 {
state BACKUP # 角色改為 BACKUP
interface eth0
virtual_router_id 51
priority 90 # 優(yōu)先級低于 Master
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.1.200/24 dev eth0
}
}啟動(dòng) Keepalived 服務(wù)
在兩臺機(jī)器上分別啟動(dòng)并設(shè)置開機(jī)自啟:
sudo systemctl enable keepalived sudo systemctl start keepalived sudo systemctl status keepalived
正常情況下,你應(yīng)該看到服務(wù)處于 active (running) 狀態(tài)。
驗(yàn)證 VIP 是否生效
在 Master 節(jié)點(diǎn)上執(zhí)行:
ip addr show eth0
你應(yīng)該能看到類似輸出:
inet 192.168.1.100/24 ... inet 192.168.1.200/24 scope global secondary eth0
說明 VIP 已成功綁定!
此時(shí)從局域網(wǎng)其他機(jī)器 ping 192.168.1.200,應(yīng)能通:
ping 192.168.1.200
模擬故障轉(zhuǎn)移
現(xiàn)在我們手動(dòng)停止 Master 節(jié)點(diǎn)的 Keepalived:
sudo systemctl stop keepalived
等待幾秒后,在 Backup 節(jié)點(diǎn)上再次執(zhí)行:
ip addr show eth0
你會(huì)發(fā)現(xiàn) VIP 192.168.1.200 已經(jīng)出現(xiàn)在 Backup 節(jié)點(diǎn)上!
同時(shí),ping 測試依然暢通,證明故障轉(zhuǎn)移成功
重啟 Master 節(jié)點(diǎn)的 Keepalived,若配置為搶占模式(默認(rèn)),VIP 會(huì)自動(dòng)切回 Master。
結(jié)合 Java 應(yīng)用:構(gòu)建高可用 HTTP 服務(wù)
光有 VIP 漂移還不夠,我們需要讓真正的業(yè)務(wù)服務(wù)——比如一個(gè) Java Web 應(yīng)用——也能隨 VIP 自動(dòng)切換訪問目標(biāo)。
為此,我們在兩臺機(jī)器上各部署一個(gè)簡單的 Spring Boot 應(yīng)用,監(jiān)聽本地端口(如 8080),并通過 VIP + Nginx 反向代理對外提供統(tǒng)一入口。
編寫 Java 示例程序
使用 Spring Boot 創(chuàng)建一個(gè)返回主機(jī)名和當(dāng)前時(shí)間的服務(wù):
// 文件:HelloController.java
package com.example.ha;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
try {
String hostname = InetAddress.getLocalHost().getHostName();
return "Hello from " + hostname + " at " + LocalDateTime.now();
} catch (UnknownHostException e) {
return "Hello from unknown host at " + LocalDateTime.now();
}
}
}// 文件:HaApplication.java
package com.example.ha;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HaApplication {
public static void main(String[] args) {
SpringApplication.run(HaApplication.class, args);
}
}打包成可執(zhí)行 JAR:
./mvnw clean package
在兩臺機(jī)器上分別運(yùn)行:
java -jar ha-demo.jar --server.port=8080
訪問各自 IP 的 http://<IP>:8080/hello,應(yīng)能看到不同主機(jī)名。
配置 Nginx 作為前端代理
為了讓外部用戶通過 VIP 訪問服務(wù),我們在兩臺機(jī)器上都安裝 Nginx,并配置反向代理到本地 Java 應(yīng)用。
安裝 Nginx:
sudo apt install -y nginx
編輯配置文件:
sudo vim /etc/nginx/sites-available/default
替換為:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}重啟 Nginx:
sudo systemctl restart nginx
現(xiàn)在,訪問 http://192.168.1.200/hello,你將看到來自 Master 節(jié)點(diǎn)的響應(yīng)。
停掉 Master 的 Keepalived,刷新頁面,你會(huì)看到響應(yīng)來源自動(dòng)切換到了 Backup 節(jié)點(diǎn)!
恭喜!你已實(shí)現(xiàn) Java 應(yīng)用的高可用架構(gòu)!
故障轉(zhuǎn)移流程圖解(mermaid)
下面用 mermaid 圖表直觀展示整個(gè)故障轉(zhuǎn)移過程:

該圖表清晰展示了客戶端始終通過 VIP 訪問服務(wù),而底層節(jié)點(diǎn)故障對用戶透明無感知。
高級配置技巧
1. 非搶占模式(nopreempt)
默認(rèn)情況下,當(dāng)原 Master 恢復(fù)后,會(huì)重新?lián)屨?VIP。如果你希望“誰先啟動(dòng)誰為主”,可在 Master 和 Backup 配置中加入:
nopreempt
并確保 Master 的 priority 仍高于 Backup。
注意:nopreempt 只在 state BACKUP 時(shí)有效,所以即使配置在 Master 上,也建議統(tǒng)一設(shè)為 BACKUP + priority 控制主從。
2. 自定義健康檢查腳本
有時(shí)我們希望在 Java 應(yīng)用崩潰時(shí),即使 Keepalived 還活著,也觸發(fā) VIP 轉(zhuǎn)移。這就需要“服務(wù)級健康檢查”。
編輯 Master 配置,加入:
vrrp_script chk_java {
script "/usr/local/bin/check_java.sh"
interval 2
weight -20 # 如果腳本失敗,降低20分優(yōu)先級
}
vrrp_instance VI_1 {
...
track_script {
chk_java
}
}創(chuàng)建檢查腳本:
sudo vim /usr/local/bin/check_java.sh
內(nèi)容:
#!/bin/bash curl -f http://localhost:8080/hello > /dev/null 2>&1 exit $?
賦予執(zhí)行權(quán)限:
sudo chmod +x /usr/local/bin/check_java.sh
重啟 Keepalived:
sudo systemctl restart keepalived
現(xiàn)在,如果 Java 應(yīng)用掛掉,VIP 會(huì)自動(dòng)漂移到 Backup!
3. 多播 vs 單播
默認(rèn) Keepalived 使用多播通信(224.0.0.18),某些云環(huán)境或容器網(wǎng)絡(luò)不支持多播,需改用單播。
在 vrrp_instance 中添加:
unicast_peer {
192.168.1.101 # Backup IP
}
Backup 節(jié)點(diǎn)則填寫 Master IP:
unicast_peer {
192.168.1.100 # Master IP
}
Java 端主動(dòng)感知 VIP 切換(可選進(jìn)階)
雖然 VIP 對客戶端透明,但在某些場景下,Java 應(yīng)用可能需要知道自己是否“當(dāng)前活躍節(jié)點(diǎn)”,以便執(zhí)行特定邏輯(如定時(shí)任務(wù)只在主節(jié)點(diǎn)運(yùn)行)。
我們可以編寫一個(gè)線程,定期檢查本機(jī)是否持有 VIP:
@Component
public class VipMonitor {
private static final String VIP = "192.168.1.200";
private volatile boolean isMaster = false;
@PostConstruct
public void startMonitoring() {
new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
boolean hasVip = checkLocalHasVip();
if (hasVip != isMaster) {
isMaster = hasVip;
System.out.println("VIP 狀態(tài)變更: " + (isMaster ? "成為主節(jié)點(diǎn)" : "降為備節(jié)點(diǎn)"));
onRoleChange(isMaster);
}
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}, "VipMonitor").start();
}
private boolean checkLocalHasVip() {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr.getHostAddress().equals(VIP)) {
return true;
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return false;
}
private void onRoleChange(boolean isNowMaster) {
if (isNowMaster) {
// 啟動(dòng)主節(jié)點(diǎn)專屬任務(wù),如:數(shù)據(jù)同步、報(bào)表生成等
scheduleMasterOnlyTasks();
} else {
// 停止主節(jié)點(diǎn)任務(wù)
cancelMasterOnlyTasks();
}
}
private void scheduleMasterOnlyTasks() {
System.out.println("啟動(dòng)主節(jié)點(diǎn)專屬定時(shí)任務(wù)...");
// 示例:每分鐘執(zhí)行一次
// yourScheduler.scheduleAtFixedRate(...);
}
private void cancelMasterOnlyTasks() {
System.out.println("取消主節(jié)點(diǎn)專屬定時(shí)任務(wù)...");
// yourScheduler.shutdown();
}
public boolean isMaster() {
return isMaster;
}
}這樣,你的 Java 應(yīng)用不僅能被動(dòng)接受流量,還能主動(dòng)參與高可用決策!
安全加固建議
雖然 Keepalived 本身輕量高效,但在生產(chǎn)環(huán)境中仍需注意安全:
- 認(rèn)證密碼復(fù)雜化:避免使用
123456這類弱密碼。 - 限制 VRRP 通信源 IP:通過防火墻規(guī)則,只允許備機(jī) IP 發(fā)送 VRRP 包。
- 啟用 unicast 替代 multicast:避免廣播風(fēng)暴或被中間人監(jiān)聽。
- 監(jiān)控日志:定期查看
/var/log/syslog或journalctl -u keepalived,及時(shí)發(fā)現(xiàn)異常切換。
生產(chǎn)環(huán)境最佳實(shí)踐
- 至少三節(jié)點(diǎn)部署:避免“腦裂”(Split Brain)問題??赏ㄟ^第三方仲裁(如 ZooKeeper、Redis)或腳本檢測決定最終主節(jié)點(diǎn)。
- VIP 與服務(wù)強(qiáng)綁定:確保 VIP 漂移時(shí),對應(yīng)服務(wù)確實(shí)可用(通過健康檢查腳本)。
- 優(yōu)雅關(guān)閉:在系統(tǒng) shutdown 前,主動(dòng)降低 Keepalived 權(quán)重,讓 VIP 提前漂移,減少服務(wù)中斷時(shí)間。
- 配合 Consul/ZooKeeper:對于微服務(wù)架構(gòu),可結(jié)合服務(wù)注冊中心,實(shí)現(xiàn)更智能的流量調(diào)度。
常見問題排查
Q1: VIP 無法綁定?
- 檢查網(wǎng)卡名稱是否正確
- 檢查子網(wǎng)掩碼是否匹配
- 檢查是否有其他進(jìn)程占用了 VIP
- 查看系統(tǒng)日志:
journalctl -u keepalived -f
Q2: 主備同時(shí)持有 VIP(腦裂)?
- 檢查網(wǎng)絡(luò)是否互通,VRRP 包能否正常收發(fā)
- 檢查
virtual_router_id是否一致 - 檢查防火墻是否放行協(xié)議 112
- 啟用
unicast_peer避免多播干擾
Q3: 健康檢查腳本不生效?
- 確保腳本有執(zhí)行權(quán)限
- 確保腳本路徑正確
- 手動(dòng)執(zhí)行腳本,確認(rèn)退出碼為 0(成功)或非 0(失敗)
- 檢查
weight設(shè)置是否合理(負(fù)值表示失敗時(shí)降權(quán))
性能與擴(kuò)展性考量
Keepalived 本身性能極高,單實(shí)例可支撐數(shù)千個(gè) VIP 和數(shù)十萬次狀態(tài)檢測。但在超大規(guī)模集群中,仍需考慮:
- 分組管理:按業(yè)務(wù)劃分多個(gè)
vrrp_instance,避免單點(diǎn)壓力過大。 - 權(quán)重動(dòng)態(tài)調(diào)整:根據(jù) CPU、內(nèi)存、連接數(shù)等指標(biāo)動(dòng)態(tài)調(diào)整節(jié)點(diǎn)權(quán)重,實(shí)現(xiàn)“智能主備”。
- 與 Kubernetes 集成:在容器化環(huán)境中,可使用 MetalLB 替代 Keepalived,專為 K8s 設(shè)計(jì)。
與其他高可用方案對比
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場景 |
|---|---|---|---|
| Keepalived | 輕量、配置簡單、成熟穩(wěn)定 | 功能較單一,依賴 VIP | LVS/Nginx/自定義服務(wù) |
| Pacemaker + Corosync | 功能強(qiáng)大,支持資源組、約束 | 配置復(fù)雜,學(xué)習(xí)成本高 | 數(shù)據(jù)庫集群、企業(yè)級 HA |
| Consul | 服務(wù)發(fā)現(xiàn)+健康檢查+KV存儲一體 | 資源占用高,需維護(hù)集群 | 微服務(wù)架構(gòu) |
| Etcd + 自研腳本 | 靈活可控 | 開發(fā)維護(hù)成本高 | 定制化需求強(qiáng)的場景 |
對于大多數(shù)中小規(guī)模 Java 應(yīng)用,Keepalived + Nginx + 健康檢查腳本的組合,是最具性價(jià)比的選擇。
總結(jié)
通過本文,我們完成了從零配置 Keepalived,實(shí)現(xiàn) VIP 故障自動(dòng)轉(zhuǎn)移,并將其與 Java Spring Boot 應(yīng)用結(jié)合,構(gòu)建了一個(gè)真正意義上的高可用服務(wù)架構(gòu)。整個(gè)過程涵蓋了:
? Keepalived 安裝與基礎(chǔ)配置
? VIP 漂移驗(yàn)證與故障模擬
? Java 應(yīng)用部署與 Nginx 反向代理整合
? 自定義健康檢查腳本增強(qiáng)可靠性
? Java 端主動(dòng)感知角色變化(進(jìn)階)
? 生產(chǎn)環(huán)境最佳實(shí)踐與安全建議
高可用不是“加個(gè)工具”就能解決的問題,而是貫穿架構(gòu)設(shè)計(jì)、服務(wù)部署、監(jiān)控告警、故障演練的系統(tǒng)工程。Keepalived 是其中重要一環(huán),幫助我們在基礎(chǔ)設(shè)施層面屏蔽單點(diǎn)故障,為上層業(yè)務(wù)保駕護(hù)航。
下一步你可以嘗試:
- 在三臺機(jī)器上部署 Keepalived,實(shí)現(xiàn)“一主兩備”。
- 編寫更復(fù)雜的健康檢查腳本,如檢測 JVM 內(nèi)存、線程池狀態(tài)。
- 將 VIP 信息寫入 Redis 或 MySQL,供其他服務(wù)讀取當(dāng)前主節(jié)點(diǎn)。
- 結(jié)合 Prometheus + Grafana,監(jiān)控 VIP 切換次數(shù)與耗時(shí)。
- 在 Docker 容器中運(yùn)行 Keepalived,探索容器化高可用方案。
結(jié)語
技術(shù)之路,貴在實(shí)踐。希望本文不僅教會(huì)你如何配置 Keepalived,更能啟發(fā)你思考系統(tǒng)穩(wěn)定性背后的本質(zhì)——冗余、檢測、切換、恢復(fù)。每一次故障轉(zhuǎn)移的背后,都是無數(shù)工程師對“永不宕機(jī)”的執(zhí)著追求。
以上就是Linux Keepalived配置虛擬IP實(shí)現(xiàn)故障轉(zhuǎn)移的全過程的詳細(xì)內(nèi)容,更多關(guān)于Linux Keepalived虛擬IP故障轉(zhuǎn)移的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
linux禁止ping的實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了linux禁止ping的實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05
linux .htaccess 設(shè)置 404 等錯(cuò)誤頁面
linux服務(wù)器下通過設(shè)置htaccess來實(shí)現(xiàn)404轉(zhuǎn)向的代碼2008-06-06
centOS6中使用crontab定時(shí)運(yùn)行執(zhí)行jar程序的腳本
這篇文章主要介紹了centOS6中使用crontab定時(shí)運(yùn)行執(zhí)行jar程序的腳本,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
Linux兩個(gè)服務(wù)器實(shí)現(xiàn)數(shù)據(jù)同步方案
這篇文章主要介紹了Linux兩個(gè)服務(wù)器實(shí)現(xiàn)數(shù)據(jù)同步方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07

