企业级高可用组件 Keepalived
Keepalived 背景描述及其方案设计
背景描述
时间:2022.6-2023.9
发布产品类型:互联网动态站点 商城
用户数量: 60000-80000(用户量猛增了4倍)
PV : 300000-5000000(24小时访问次数总和)
DAU: 25000(每日活跃用户数)
随着用户量增多,总的页面数量一直在持续增加,可以预料到的是,WEB服务器,压力会越来越大,虽然部署了集群和负载均衡,前端依然存在单点故障。如果一旦 Nginx 宕机,用户就完全失去服务了,用户体验特别不好,这就是造成了所谓的单点故障。
解决方案:
需要备用一台前端负载均衡服务器进行使用,如果出现宕机,切换为备用服务器。
梳理思路:
Nginx 解决的是两台 Web 服务器之间的负载均衡问题,但是没解决 Nginx 自己的高可用问题。
引入 高可用组件 Keepalived,当 Nginx 本身挂了,还有另一个 Nginx 可用。
运维方案设计

针对业务背景下的需求,升级为以下架构:

单点故障
过去我们可能依赖 单台负载均衡服务器(如 proxy1) 处理所有流量,但它存在巨大风险:
- 一旦这台服务器宕机(硬件故障、进程崩溃、网络中断),所有依赖它的服务会 立即中断(如用户无法访问网站、支付系统瘫痪)。
- 人工恢复耗时且不可靠:需紧急排查问题、重启服务或切换服务器,期间业务持续受损。
高可用集群
HA(High Availability) 是 高可用性 的缩写。
HA Cluster(高可用集群)是通过 多节点协作 保障业务 持续稳定运行 的解决方案,至少 2 个节点,通常更多。
高可用架构设计的核心准则是:冗余 + 故障切换 FailOver —— 不要把鸡蛋放在一个篮子里。
冷备份 vs 热备份
根据备用节点的 状态和切换速度,高可用方案分为两类:
- 冷备(Cold Standby)—— “紧急备用,但需手动”
特点:备用服务器 平时不运行服务(不启用、不解析域名),仅作为“灾备物资”存放。
缺点:恢复时间长(可能分钟级甚至小时级),业务中断明显。
- 热备(Hot Standby)—— “时刻待命,自动接管”
特点:备用服务器 始终处于运行状态(监控主节点健康),实时同步,随时准备接管。
关键支持:依赖 虚拟 IP(VIP)漂移(主备节点共享同一个对外 IP,故障时 VIP 自动绑定到备用节点)和 健康监测(如心跳检测、服务端口检查)。

Keepalived 整体概述(理解)
核心概念
Keepalived 是一个基于 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议) 协议开发的开源软件,最初设计用于为 LVS(Linux Virtual Server,Linux虚拟服务器) 提供**高可用性(HA)**支持。
后来扩展为通用的 IP 漂移(VIP 漂移)和高可用解决方案,广泛应用于 Web 服务、数据库、负载均衡等场景的故障切换。
核心目标:
通过主备/主主节点的自动故障检测与切换,确保关键服务对外提供访问的 IP(VIP)始终可用,避免单点故障。
Redundancy 音 /rɪˈdʌndənsi/ 瑞当登西,意 冗余的,多余的。
核心功能
| 功能 | 说明 |
|---|---|
| VRRP 协议实现 | 通过组播心跳协商主备角色,主节点持有 VIP,备节点监听并抢占。 |
| VIP 漂移 | 主节点故障时,备节点自动绑定 VIP 并通知局域网(通过 ARP)。 |
| 健康检查 | 监测本地服务(如进程、端口、HTTP),异常时主动降权或触发切换。 |
| 轻量级部署 | 基于 Linux 系统,仅需安装软件包并配置,资源占用低。 |
组成原理
Keepalived 的高可用功能基于 虚拟路由冗余协议 VRRP 实现,其核心思想是在多个节点(主/备)之间协商“谁是当前的主节点(Master)”,并由
主节点持有虚拟 IP(VIP);
备节点(Backup)监听主节点状态,主节点故障时快速接管 VIP。
工作流程
初始化
集群中所有节点(Master/Backup)配置相同的 VRID(虚拟路由标识符) 和 虚拟IP(VIP)。其中 Master节点初始优先级最高(如100),Backup节点优先级较低(如90),通过优先级确定主备角色。
Master 心跳
Master节点通过周期性(默认1秒间隔)向局域网广播,报文中包含自身 优先级、VRID、状态(Master) 等关键信息,用于宣告其对VIP的所有权,意思是”我是主节点!“。
Backup 监听
Backup节点持续监听组播报文;若在 Master_Down_Interval(默认3×通告间隔=3秒)超时时间内未收到有效的Master通告报文,则判定当前Master节点失效(如宕机或网络隔离)。
角色切换
当Backup节点确认Master节点失效后,优先级最高的Backup节点 自动升级为新的Master节点:
- 立即开始周期性发送通告报文;
- 通过内核网络接口绑定VIP,并更新局域网ARP表(通过免费ARP通告VIP对应的自身MAC地址),确保终端设备可将VIP流量路由至本节点。
原 Master 恢复
若原Master节点故障恢复并重新加入集群:
- 抢占模式(默认启用):若原Master节点优先级仍高于当前Master节点(如恢复后优先级100 > 当前90),则原Master节点通过更高优先级的通告报文夺回主角色,原Backup节点降级;
- 非抢占模式:原Master节点即使优先级更高也不主动抢占,维持当前Master节点继续持有VIP(需手动干预或关闭非抢占配置)。
核心机制:基于组播心跳维持主备状态同步,通过优先级竞争实现故障自动切换,结合ARP动态维护VIP的可达性。
Keepalived HA 高可用服务搭建(掌握)
环境准备
CentOS Stream release 9
| 角色 | IP | 主机名 | 功能 | 备注 |
|---|---|---|---|---|
| proxy1 | 192.168.88.101/192.168.88.102 | proxy1.itcast.cn | Keepalived/Nginx代理 | Keepalived/代理1 |
| proxy2 | 192.168.88.102/192.168.88.103 | proxy2.itcast.cn | Keepalived/Nginx代理 | Keepalived/代理2 |
| slave | 192.168.88.104/192.168.88.105 | slave.itcast.cn | MySQL从库(可选) | 从库(可选) |
修改主机名和 hosts
hostnamectl set-hostname proxy1 && bash
hostnamectl set-hostname proxy2 && bash
hostnamectl set-hostname slave && bash # 可选
cat >/etc/hosts<<EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.88.101 proxy1 proxy1.itcast.cn
192.168.88.102 proxy2 proxy2.itcast.cn
EOF
cat >/etc/hosts<<EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.88.102 proxy1 proxy1.itcast.cn
192.168.88.103 proxy2 proxy2.itcast.cn
192.168.88.104 slave slave.itcast.cn
EOF


关闭防火墙与 SELinux
iptables -F
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config
配置 yum 源
阿里源(推荐)
cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
清华源(了解)
CentOS Stream 9 默认启用了包管理工具 dnf,其是 yum 包管理工具的替代品。dnf 与 yum 大部分的命令都是通用的,dnf 也使用 /etc/yum.repos.d/ 进行镜像配置。
CentOS Stream 9 中源被整合入两个文件 centos.repo 和 centos-addons.repo,由于文件中不包含 baseurl 字段,需要手动插入,通过文本替换修改源的方法较为复杂,也可以选择直接复制最后的替换结果覆盖源文件。
将这段代码保存为一个文件,例如 update_mirror.pl
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
my $mirrors = 'https://mirrors.tuna.tsinghua.edu.cn/centos-stream';
if (@ARGV < 1) {
die "Usage: $0 <filename1> <filename2> ...\n";
}
while (my $filename = shift @ARGV) {
my $backup_filename = $filename . '.bak';
rename $filename, $backup_filename;
open my $input, "<", $backup_filename;
open my $output, ">", $filename;
while (<$input>) {
s/^metalink/# metalink/;
if (m/^name/) {
my (undef, $repo, $arch) = split /-/;
$repo =~ s/^\s+|\s+$//g;
($arch = defined $arch ? lc($arch) : '') =~ s/^\s+|\s+$//g;
if ($repo =~ /^Extras/) {
$_ .= "baseurl=${mirrors}/SIGs/\$releasever-stream/extras" . ($arch eq 'source' ? "/${arch}/" : "/\$basearch/") . "extras-common\n";
} else {
$_ .= "baseurl=${mirrors}/\$releasever-stream/$repo" . ($arch eq 'source' ? "/" : "/\$basearch/") . ($arch ne '' ? "${arch}/tree/" : "os") . "\n";
}
}
print $output $_;
}
}
然后,在命令行中使用以下命令来执行它:
dnf install perl-autodie -y
perl ./update_mirror.pl /etc/yum.repos.d/centos*.repo
注意:如果清华源无法使用,我们也可以基于阿里源
cp /etc/yum.repos.d/centos.repo /etc/yum.repos.d/centos.repo.bak
cp /etc/yum.repos.d/centos-addons.repo /etc/yum.repos.d/centos-addons.repo.bak
centos.repo
[baseos]
name=CentOS Stream $releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/BaseOS/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream $releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/BaseOS/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream $releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream $releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/AppStream/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream $releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/AppStream/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream $releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/AppStream/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream $releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/CRB/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream $releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/CRB/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream $releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
centos-addons.repo
[highavailability]
name=CentOS Stream $releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/HighAvailability/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream $releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/HighAvailability/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream $releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream $releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/NFV/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream $releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/NFV/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream $releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream $releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/RT/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream $releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/RT/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream $releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream $releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/ResilientStorage/$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream $releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/ResilientStorage/$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream $releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream $releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/$stream/extras/$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream $releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
最后,更新软件包缓存(可选):
# 使用 dnf
dnf clean all && dnf makecache
# 使用 yum
yum clean all && yum makecache
注意,如果需要启用其中一些 repo,需要将其中的 enabled=0 改为 enabled=1。
设置网络(可选)
ls /etc/NetworkManager/system-connections/
vi /etc/NetworkManager/system-connections/ens160.nmconnection
------------------------------------------------------ 设置开始 -------------------------------------------------------------
[ipv4]
method=manual
addresses=192.168.88.101/24
gateway=192.168.88.2
dns=114.114.114.114
[ipv6]
method=ignore
------------------------------------------------------ 设置结束 -------------------------------------------------------------
systemctl restart NetworkManager
nmcli device show ens160
如果不想重启整个 NetworkManager 服务,可以只重新激活特定的网络连接:
nmcli connection down <连接名称>
nmcli connection up <连接名称>
nmcli connection down ens160
nmcli connection up ens160
如果想重启所有网络接口,可以使用以下命令:
nmcli networking off
nmcli networking on
当然,你也可以使用传统方式,如:ifup,ifdown等等
ntpdate 时间同步(可选)
yum install epel-release -y
yum install ntpsec -y
ntpdate cn.ntp.org.cn

安装必备软件(推荐)
yum install vim net-tools rsync -y
安装配置 Keepalived
前提:让proxy1机器与proxy2机器保持配置完全一致(主机名称与IP地址要区分开)
keepalived可以使用通过yum方式或者源码编译的方式实现。
在目前案列实现中,通过yum安装的版本即可。
使用yum方式安装
master和backup都需要进行安装,所以给proxy1和proxy2进行安装keepalived
yum install keepalived -y
keepalived -v


Keepalived不需要自己单独的主机吗?
是的,对谁(比如这里的Nginx负载均衡)做高可用,就直接在集群上面安装部署即可。
配置文件:
# /etc/keepalived/keepalived.conf
[root@proxy1 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16
192.168.200.17
192.168.200.18
}
}
virtual_server 192.168.200.100 443 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
real_server 192.168.201.100 443 {
weight 1
SSL_GET {
url {
path /
digest ff20ad2481f97b1754ef3e12ecd3a9cc
}
url {
path /mrtg/
digest 9b3a0c85a887a256d6939da88aabd8cd
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
virtual_server 10.10.10.2 1358 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
sorry_server 192.168.200.200 1358
real_server 192.168.200.2 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
virtual_server 10.10.10.3 1358 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
real_server 192.168.200.4 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
real_server 192.168.200.5 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
[root@proxy1 ~]#
注意事项:
启动keepalived之前,一定要配置好/etc/keepalived/keepalived.conf
192.168.88.102(MASTER)/etc/keepalived/keepalived.conf
cat >/etc/keepalived/keepalived.conf<<EOF
! Configuration File for keepalived
global_defs {
router_id ka102 # 本机标识,两台不能重复
}
vrrp_instance VI_1 {
state MASTER
interface ens160 # <-- 改成实际网卡名
virtual_router_id 88 # 0-255,两台必须一致
priority 100 # 主节点更高
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
EOF
192.168.88.103(BACKUP)/etc/keepalived/keepalived.conf
cat >/etc/keepalived/keepalived.conf<<EOF
! Configuration File for keepalived
global_defs {
router_id ka103 # 与对端不同
}
vrrp_instance VI_1 {
state BACKUP
interface ens160 # 同上,改成实际网卡
virtual_router_id 88 # 必须与 MASTER 一致
priority 90 # 比主节点低
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
EOF
日志文件:
# /var/log/messages
设置VIP注意事项:
① 用户可以访问VIP,VIP所在的机器没有限制外网访问 ② VIP是没有被占用的
以下实现,VIP选择同网段的。
启动 Keepalived
通过yum方式安装的keepalived,直接使用systemctl命令进行管理,如果是通过源码包安装的可以使用keepalived -D 参数启动。
注意:先在proxy1上启动keepalived,然后再到proxy2上启动keepalived
systemctl start keepalived
systemctl enable keepalived
systemctl status keepalived --no-pager
# systemctl stop keepalived
查看主备服务器的网卡信息
MASTER的网卡信息:
ip a
或者
ifconfig
BACKUP的网卡信息:
ip a
或者
ifconfig
通过keepalived的主备模式,实现默认VIP绑定到了master服务器
MASTER服务器宕机了(关机,断电了,网线断了),VIP会切换到了BACKUP
MASTER
[root@proxy1 ~]# systemctl start keepalived
[root@proxy1 ~]# systemctl enable keepalived
Created symlink /etc/systemd/system/multi-user.target.wants/keepalived.service → /usr/lib/systemd/system/keepalived.service.
[root@proxy1 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; preset: disabled)
Active: active (running) since Thu 2025-12-11 23:27:30 CST; 5min ago
Main PID: 31463 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 1.8M
CPU: 65ms
CGroup: /system.slice/keepalived.service
├─31463 /usr/sbin/keepalived --dont-fork -D
└─31464 /usr/sbin/keepalived --dont-fork -D
Dec 11 23:27:34 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:34 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:34 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:34 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: (VI_1) Sending/queueing gratuitous ARPs on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
Dec 11 23:27:39 proxy1 Keepalived_vrrp[31464]: Sending gratuitous ARP on ens160 for 192.168.88.200
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59109 bytes 82166292 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21740 bytes 1366362 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]#
BACKUP
[root@proxy2 ~]# systemctl start keepalived
[root@proxy2 ~]# systemctl enable keepalived
Created symlink /etc/systemd/system/multi-user.target.wants/keepalived.service → /usr/lib/systemd/system/keepalived.service.
[root@proxy2 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; preset: disabled)
Active: active (running) since Thu 2025-12-11 23:32:29 CST; 1min 47s ago
Main PID: 31699 (keepalived)
Tasks: 2 (limit: 22926)
Memory: 1.8M
CPU: 17ms
CGroup: /system.slice/keepalived.service
├─31699 /usr/sbin/keepalived --dont-fork -D
└─31700 /usr/sbin/keepalived --dont-fork -D
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: Registering Kernel netlink reflector
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: Registering Kernel netlink command channel
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: Assigned address 192.168.88.103 for interface ens160
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: Registering gratuitous ARP shared channel
Dec 11 23:32:29 proxy2 Keepalived[31699]: Startup complete
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: (VI_1) removing VIPs.
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: (VI_1) removing VIPs.
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: (VI_1) Entering BACKUP STATE (init)
Dec 11 23:32:29 proxy2 Keepalived_vrrp[31700]: VRRP sockpool: [ifindex( 2), family(IPv4), proto(112), fd(12,13) multicast, addres>
Dec 11 23:32:29 proxy2 systemd[1]: Started LVS and VRRP High Availability Monitor.
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 60487 bytes 82026148 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23567 bytes 1512933 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]#
常见问题说明:
问题1:keepalived启动了,但是没有产生VIP
答:大部分情况都是因为网卡名称写错了,最好在配置前使用ip a确认物理网卡名称:ens160或ens160或ens160
问题2:keepalived启动了,但是两台机器上都有VIP(脑裂)
答:在同一个HA Cluster组中有两个VIP,每台机器都认为自己是主服务器,核心原因在于网络通信异常,意识不到对方的存在。① 网络故障 ② 防火墙没关,vrrp协议默认无法通过防火墙。firewall-cmd --add-protocol=vrrp
问题3:脑裂有什么危害?
答:如果一个组中有两个VIP,就会出现资源争抢情况。
问题4:抢占模式
默认state master和backup模式,优先master,如果一旦master恢复,就会把VIP重新切换master上,本来没有问题,但是对于用户的友好性不好。如果master恢复,不争抢作为备机更好。
可以通过把两台服务器的state状态,都调整为backup,就不存在恢复争抢的问题。
非抢占模式
MASTER节点
[root@proxy1 ~]# vim /etc/keepalived/keepalived.conf
[root@proxy1 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id ka102 # 本机标识,两台不能重复
}
vrrp_instance VI_1 {
state BACKUP
interface ens160 # <-- 改成实际网卡名
virtual_router_id 88 # 0-255,两台必须一致
priority 100 # 改成相同的数字
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
nopreempt # 加上这个参数更加稳妥
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
[root@proxy1 ~]# systemctl restart keepalived
[root@proxy1 ~]# systemctl status keepalived --no-pager
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; preset: disabled)
Active: active (running) since Wed 2026-03-25 15:54:50 CST; 5s ago
Main PID: 35039 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 1.8M
CPU: 18ms
CGroup: /system.slice/keepalived.service
├─35039 /usr/sbin/keepalived --dont-fork -D
└─35041 /usr/sbin/keepalived --dont-fork -D
Mar 25 15:54:52 proxy1 Keepalived_vrrp[35041]: (VI_1) received lower priori…ing
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: (VI_1) Receive advertisement…out
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: (VI_1) Entering MASTER STATE
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: (VI_1) setting VIPs.
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: (VI_1) Sending/queueing grat…200
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: Sending gratuitous ARP on en…200
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: Sending gratuitous ARP on en…200
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: Sending gratuitous ARP on en…200
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: Sending gratuitous ARP on en…200
Mar 25 15:54:53 proxy1 Keepalived_vrrp[35041]: Sending gratuitous ARP on en…200
Hint: Some lines were ellipsized, use -l to show in full.
[root@proxy1 ~]#
BACKUP节点
[root@proxy2 ~]# vim /etc/keepalived/keepalived.conf
[root@proxy2 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id ka103 # 与对端不同
}
vrrp_instance VI_1 {
state BACKUP
interface ens160 # 同上,改成实际网卡
virtual_router_id 88 # 必须与 MASTER 一致
priority 100 # 改成相同的数字
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
nopreempt # 加上这个参数更加稳妥
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
[root@proxy2 ~]# systemctl restart keepalived
[root@proxy2 ~]# systemctl status keepalived --no-pager
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; preset: disabled)
Active: active (running) since Wed 2026-03-25 15:58:41 CST; 4s ago
Main PID: 33265 (keepalived)
Tasks: 2 (limit: 22926)
Memory: 1.8M
CPU: 21ms
CGroup: /system.slice/keepalived.service
├─33265 /usr/sbin/keepalived --dont-fork -D
└─33266 /usr/sbin/keepalived --dont-fork -D
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: Registering Kernel netlink r…tor
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: Registering Kernel netlink c…nel
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: Assigned address 192.168.88.…160
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: Registering gratuitous ARP s…nel
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: (VI_1) removing VIPs.
Mar 25 15:58:41 proxy2 Keepalived[33265]: Startup complete
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: (VI_1) removing VIPs.
Mar 25 15:58:41 proxy2 systemd[1]: Started LVS and VRRP High Availability …tor.
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: (VI_1) Entering BACKUP STATE…it)
Mar 25 15:58:41 proxy2 Keepalived_vrrp[33266]: VRRP sockpool: [ifindex( 2)…8)]
Hint: Some lines were ellipsized, use -l to show in full.
[root@proxy2 ~]#
Keepalived VIP 漂移
抢占模式
vim /etc/keepalived/keepalived.conf
state MASTER # proxy1
state BACKUP # proxy2
systemctl restart keepalived
[root@proxy1 ~]# grep state /etc/keepalived/keepalived.conf
state MASTER
[root@proxy2 ~]# grep state /etc/keepalived/keepalived.conf
state BACKUP
[root@proxy2 ~]#
MASTER 节点
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59218 bytes 82175614 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22290 bytes 1399290 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl stop keepalived
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59290 bytes 82181608 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22340 bytes 1403718 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]#
BACKUP 节点
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 60487 bytes 82026148 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23567 bytes 1512933 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 61031 bytes 82062642 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23614 bytes 1516235 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]#
MASTER 节点
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59290 bytes 82181608 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22340 bytes 1403718 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl start keepalived
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59218 bytes 82175614 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22290 bytes 1399290 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
BACKUP 节点
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 61031 bytes 82062642 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23614 bytes 1516235 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 60487 bytes 82026148 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23567 bytes 1512933 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
非抢占模式
vim /etc/keepalived/keepalived.conf
state BACKUP # proxy1
state BACKUP # proxy2
nopreempt # 加上这个参数更加稳妥
systemctl restart keepalived
注意:
把原来的 MASTER keepalived 配置文件里面的优先级改一下
优先级改为跟原来的 BACKUP 的优先级一样
把 priority 100 改为 priority 90
[root@proxy1 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id ka102 # 本机标识,两台不能重复
}
vrrp_instance VI_1 {
# state MASTER
state BACKUP
interface ens160 # <-- 改成实际网卡名
virtual_router_id 88 # 0-255,两台必须一致
priority 100 # 主节点更高
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
[root@proxy1 ~]# vim /etc/keepalived/keepalived.conf
[root@proxy1 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id ka102 # 本机标识,两台不能重复
}
vrrp_instance VI_1 {
# state MASTER
state BACKUP
interface ens160 # <-- 改成实际网卡名
virtual_router_id 88 # 0-255,两台必须一致
priority 90
advert_int 1 # 是 VRRP 报文的发送间隔,单位秒
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
[root@proxy1 ~]# systemctl restart keepalived
[root@proxy1 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; preset: disabled)
Active: active (running) since Tue 2026-05-26 12:07:25 CST; 3s ago
Main PID: 42083 (keepalived)
Tasks: 2 (limit: 22926)
Memory: 1.8M
CPU: 12ms
CGroup: /system.slice/keepalived.service
├─42083 /usr/sbin/keepalived --dont-fork -D
└─42084 /usr/sbin/keepalived --dont-fork -D
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: Registering Kernel netlink reflector
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: Registering Kernel netlink command channel
May 26 12:07:25 proxy1 systemd[1]: Started LVS and VRRP High Availability Monitor.
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: Assigned address 192.168.88.102 for interface ens160
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: Registering gratuitous ARP shared channel
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: (VI_1) removing VIPs.
May 26 12:07:25 proxy1 Keepalived[42083]: Startup complete
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: (VI_1) removing VIPs.
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: (VI_1) Entering BACKUP STATE (init)
May 26 12:07:25 proxy1 Keepalived_vrrp[42084]: VRRP sockpool: [ifindex( 2), family(IPv4), proto(112), fd(12,13) multicast, add>
[root@proxy1 ~]#
[root@proxy1 ~]# grep state /etc/keepalived/keepalived.conf
state BACKUP
[root@proxy2 ~]# grep state /etc/keepalived/keepalived.conf
state BACKUP
[root@proxy2 ~]#
BACKUP 节点(原 MASTER 节点)
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59218 bytes 82175614 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22290 bytes 1399290 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl stop keepalived
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59290 bytes 82181608 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22340 bytes 1403718 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl start keepalived # 再次启动keepalived
[root@proxy1 ~]# ifconfig # VIP不会被抢回来
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 59360 bytes 82187651 (78.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22371 bytes 1406868 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]#
BACKUP 节点
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 61058 bytes 82065039 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23778 bytes 1525711 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 61058 bytes 82065039 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23778 bytes 1525711 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]# ifconfig # VIP仍然在BACKUP节点
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 61058 bytes 82065039 (78.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23778 bytes 1525711 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]#
让 Keepalived 与 CRMEB 建立联系(拓展)
第一步:更改 Windows 中域名解析( hosts 文件)
192.168.88.200 www.itheimashop.com
第二步:注释掉 keepalived 配置文件中的 vrrp_strict,如果不注释,VIP 无法 ping 通
特别注意:1.3 以后版本要注释 vrrp_strict,否则虚拟 IP 无法 ping 通
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.163
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
第三步:配置 proxy1 和 proxy2 代理到 CRMEB 的后端服务器
iptables 网络代理转发(拓展)

[root@server3 ~]# ls /etc/NetworkManager/system-connections/
ens160.nmconnection ens224.nmconnection
[root@server3 ~]# cat /etc/NetworkManager/system-connections/ens160.nmconnection
[connection]
id=ens160
#uuid=39fc68b0-865c-3bd3-a42d-3e1998f8e2cd
type=ethernet
autoconnect-priority=-999
interface-name=ens160
timestamp=1752853607
[ethernet]
[ipv4]
#method=auto
method=manual
addresses=192.168.88.103/24
gateway=192.168.88.2
dns=192.168.88.2,114.114.114.114;
[ipv6]
#addr-gen-mode=eui64
#method=auto
method=disabled
[proxy]
[root@server3 ~]# cat /etc/NetworkManager/system-connections/ens224.nmconnection
[connection]
id=ens224
#uuid=39fc68b0-865c-3bd3-a42d-3e1998f8e2cd
type=ethernet
autoconnect-priority=-999
interface-name=ens160
timestamp=1752853607
[ethernet]
[ipv4]
method=auto
[ipv6]
#addr-gen-mode=eui64
#method=auto
method=disabled
[proxy]
[root@server3 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 23397 bytes 27937946 (26.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12275 bytes 3541901 (3.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens224: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.11.32 netmask 255.255.255.0 broadcast 192.168.11.255
ether 00:0c:29:e6:d9:8a txqueuelen 1000 (Ethernet)
RX packets 3694 bytes 2680395 (2.5 MiB)
RX errors 0 dropped 180 overruns 0 frame 0
TX packets 596 bytes 58983 (57.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@server3 ~]#
echo 1 > /proc/sys/net/ipv4/ip_forward
sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
sysctl -p
iptables -t nat -F
iptables -t nat -A PREROUTING -d 192.168.88.103 -p tcp --dport 80 -j DNAT --to-destination 192.168.11.22:80
iptables -t nat -A POSTROUTING -d 192.168.11.22 -p tcp --dport 80 -j SNAT --to-source 192.168.11.32
iptables -A FORWARD -j ACCEPT
[root@server3 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.22:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT tcp -- anywhere 192.168.11.22 tcp dpt:http to:192.168.11.32
[root@server3 ~]#
# CentOS/RHEL7及之前
service iptables save
# 或者
iptables-save > /etc/sysconfig/iptables
# 带日期保存
iptables-save > /root/iptables-backup-$(date +%Y%m%d).rules
# 恢复规则
iptables-restore < /etc/sysconfig/iptables
iptables-restore < /root/iptables-backup-日期.rules
iptables-restore < /root/iptables-backup-20260114.rules





拓展操作
[root@server3 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@server3 ~]# sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
[root@server3 ~]# sysctl -p
[root@server3 ~]# iptables -t nat -A POSTROUTING -d 192.168.11.0/24 -p tcp --dport 80 -j SNAT --to-source 192.168.11.60
[root@server3 ~]# iptables -t nat -A PREROUTING -d 192.168.88.103 -p tcp --dport 80 -j DNAT --to-destination 192.168.11.29:80
[root@server3 ~]# iptables -t nat -A PREROUTING -d 192.168.88.103 -p tcp --dport 80 -j DNAT --to-destination 192.168.11.198:80
[root@server3 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.29:80
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.198:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT tcp -- anywhere 192.168.11.0/24 tcp dpt:http to:192.168.11.60
[root@server3 ~]# iptables -t nat -D PREROUTING 1
[root@server3 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.198:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT tcp -- anywhere 192.168.11.0/24 tcp dpt:http to:192.168.11.60
[root@server3 ~]# iptables -t nat -D POSTROUTING 1
[root@server3 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.198:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
[root@server3 ~]#
实现 Nginx 服务 HA 高可用(重点)
优化 Linux 操作系统
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
HA 目标
- 任意一台 nginx 挂 → keepalived 立即降低权重/自杀 → VIP 漂到对端
- 两台 nginx 正常时,VIP 默认落在 proxy1(MASTER)
- 浏览器访问
http://vip或域名即可看到后端服务器 192.168.88.101 的内容
HA 环境
- 两台调度器:proxy1(102) / proxy2(103)
- VIP:192.168.88.200
- 后端真实 Web:192.168.88.101:80

特别注意:1.3以后版本要注释vrrp_strict,否则虚拟IP无法ping通
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.163
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
后端域名解析
把业务域名解析到 VIP 即可,例如
192.168.88.200 www.itheimashop.com
C:\Windows\System32\drivers\etc
vim /etc/hosts
Windows和Linux的hosts文件都要配置域名解析,后续所有用户都访问域名,不再直接写 101。
nginx 层:两台代理服务器配置一模一样
记得两台代理服务器要安装Nginx
选择dnf/yum安装Nginx或者源码安装Nginx都可以
阿里源:
cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
清华源:
cat >/etc/yum.repos.d/tsinghua.repo<<'EOF'
[baseos]
name=CentOS Stream $releasever - BaseOS
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debuginfo]
name=CentOS Stream $releasever - BaseOS - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream $releasever - BaseOS - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream $releasever - AppStream
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debuginfo]
name=CentOS Stream $releasever - AppStream - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream $releasever - AppStream - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream $releasever - CRB
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[crb-debuginfo]
name=CentOS Stream $releasever - CRB - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream $releasever - CRB - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
dnf install -y nginx
systemctl start nginx
systemctl enable nginx
systemctl status nginx


dnf/yum安装的nginx:
改 /etc/nginx/nginx.conf 配置
cp /etc/nginx/nginx.conf{,.bak} # 可选备份
cat > /etc/nginx/nginx.conf <<'EOF'
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.88.101:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
EOF
nginx -t
nginx -s reload
源码安装的nginx:
改 /usr/local/nginx/conf/nginx.conf 配置
cp /usr/local/nginx/conf/nginx.conf{,.bak} # 可选备份
cat > /usr/local/nginx/conf/nginx.conf <<'EOF'
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.88.101:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
EOF
nginx -t
nginx -s reload
对接后端多台服务器(可选)
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.88.106:80 max_fails=2 fail_timeout=3s;
server 192.168.88.107:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
保存后两台都重新加载:
nginx -t # 先检查语法
nginx -s reload # 重新加载nginx配置


keepalived 层:引入 track_script 实时检查 nginx 存活
- nginx 检测脚本(两台路径一样,内容一样)
基础版(不结合weight降权)
开发和测试环境,我们使用这个基础版脚本,容易看到效果。
cat > /etc/keepalived/check_nginx.sh <<'EOF'
#!/bin/bash
# 如果 nginx 进程消失 或 80 端口不响应,就认为是 DOWN
if ! pgrep -x nginx &>/dev/null || ! ss -lnt | grep -q ':80'; then
systemctl stop keepalived # 释放 VIP
fi
EOF
chmod +x /etc/keepalived/check_nginx.sh
优化改进版(结合weight降权)
cat > /etc/keepalived/check_nginx.sh <<'EOF'
#!/bin/bash
# exit 0 = 健康,exit 1 = 故障(keepalived 自动降权触发 VRRP 切换)
pgrep -x nginx &>/dev/null \
&& curl -sf --max-time 2 http://127.0.0.1/ &>/dev/null \
&& exit 0
exit 1
EOF
| 对比项 | 基础版 | 优化改进版 |
|---|---|---|
| 故障处理方式 | systemctl stop keepalived,强制停止服务 | exit 1,通知 keepalived 自行处理 |
| VIP 释放方式 | 脚本主动释放 | keepalived 通过 VRRP 选举自然切换 |
| 自动恢复 | ❌ nginx 恢复后需手动启动 keepalived | ✅ nginx 恢复后 keepalived 自动重新竞选 |
| 检测手段 | pgrep 进程 + ss 端口监听 | pgrep 进程 + curl HTTP 响应 |
| 检测准确性 | 端口监听 ≠ 业务正常 | 实际 HTTP 响应,更贴近真实可用性 |
| 结合 weight | 不支持(直接 stop,无优先级概念) | 支持,配合 weight -30 实现降权切换 |
核心区别一句话:基础版是脚本自己动手停服务,优化版是脚本汇报状态、让 keepalived 去决策。
- 修改主机配置文件(proxy1 —— MASTER)
cat > /etc/keepalived/keepalived.conf <<'EOF'
global_defs {
router_id ka102
# vrrp_strict # <-- 必须注释
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2 # 每 2 秒检测一次
# weight -30 # 检测失败时 priority 降低 30
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 88
priority 100
advert_int 1 # 每秒发一次心跳
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
check_nginx
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
EOF
- 修改备机配置文件(proxy2 —— BACKUP)
cat > /etc/keepalived/keepalived.conf <<'EOF'
global_defs {
router_id ka103
# vrrp_strict
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
# weight -30
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 88
priority 90
advert_int 1 # 每秒发一次心跳
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
check_nginx
}
virtual_ipaddress {
192.168.88.200/24 dev ens160 label ens160:1
}
}
EOF
- 刷新当前keepalived和nginx的服务配置,严格按照顺序来执行(防止一启动就自杀)
# 两台都执行,先主后备
systemctl stop keepalived
nginx -s reload # 确保 nginx 已运行 systemctl start nginx
systemctl status nginx
systemctl start keepalived
systemctl enable keepalived
systemctl status keepalived
验证高可用
-
浏览器访问
http://192.168.88.200或者 http://www.itheimashop.com 预计能看到 192.168.88.101 的页面。 -
在 proxy1 手动关 nginx:
systemctl stop nginx 或者 pkill nginx -
- 2 秒内 check_nginx.sh 会触发
systemctl stop keepalived - VIP 漂到 proxy2(
ifconig 或者 ip a能看到 ens160:1) - 刷新浏览器,业务不中断
- 2 秒内 check_nginx.sh 会触发
-
把 proxy1 的 nginx 重新启动,再启 keepalived,VIP 会回到 priority 更高的 proxy1(MASTER 默认抢占)。


分别检查主机和备机状态
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 53194 bytes 71580572 (68.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 24155 bytes 3709381 (3.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 2 bytes 168 (168.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 168 (168.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Fri 2025-12-12 22:00:42 CST; 1h 3min ago
Main PID: 9291 (nginx)
Tasks: 3 (limit: 22927)
Memory: 7.5M
CPU: 191ms
CGroup: /system.slice/nginx.service
├─9291 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
├─9462 "nginx: worker process"
└─9463 "nginx: worker process"
Dec 12 22:00:42 proxy1 systemd[1]: Starting Nginx Web Server...
Dec 12 22:00:42 proxy1 systemd[1]: Started Nginx Web Server.
[root@proxy1 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: active (running) since Fri 2025-12-12 22:58:30 CST; 5min ago
Main PID: 9466 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 4.5M
CPU: 3.070s
CGroup: /system.slice/keepalived.service
├─9466 /usr/sbin/keepalived --dont-fork -D
└─9467 /usr/sbin/keepalived --dont-fork -D
Dec 12 22:58:34 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:34 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:34 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:34 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: (VI_1) Sending/queueing gratuito>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
Dec 12 22:58:39 proxy1 Keepalived_vrrp[9467]: Sending gratuitous ARP on ens160>
[root@proxy1 ~]#
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 55455 bytes 71728550 (68.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 17647 bytes 3287463 (3.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Fri 2025-12-12 22:00:51 CST; 1h 3min ago
Main PID: 9283 (nginx)
Tasks: 3 (limit: 22927)
Memory: 7.6M
CPU: 91ms
CGroup: /system.slice/nginx.service
├─9283 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
├─9373 "nginx: worker process"
└─9374 "nginx: worker process"
Dec 12 22:00:51 proxy2 systemd[1]: Starting Nginx Web Server...
Dec 12 22:00:51 proxy2 systemd[1]: Started Nginx Web Server.
[root@proxy2 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: active (running) since Fri 2025-12-12 22:58:42 CST; 5min ago
Main PID: 9378 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 5.1M
CPU: 3.315s
CGroup: /system.slice/keepalived.service
├─9378 /usr/sbin/keepalived --dont-fork -D
└─9379 /usr/sbin/keepalived --dont-fork -D
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: SECURITY VIOLATION - scripts are>
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: Assigned address 192.168.88.103 >
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: Registering gratuitous ARP share>
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: (VI_1) removing VIPs.
Dec 12 22:58:42 proxy2 Keepalived[9378]: Startup complete
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: (VI_1) removing VIPs.
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: (VI_1) Entering BACKUP STATE (in>
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: VRRP sockpool: [ifindex( 2), fa>
Dec 12 22:58:42 proxy2 systemd[1]: Started LVS and VRRP High Availability Moni>
Dec 12 22:58:42 proxy2 Keepalived_vrrp[9379]: VRRP_Script(check_nginx) succeed>
[root@proxy2 ~]#
模拟故障,主机停掉nginx服务
[root@proxy1 ~]# systemctl stop nginx
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 55960 bytes 74219443 (70.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27783 bytes 6339362 (6.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 2 bytes 168 (168.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 168 (168.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]# systemctl status keepalived
○ keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: inactive (dead) since Fri 2025-12-12 23:05:50 CST; 4s ago
Duration: 7min 18.109s
Process: 9466 ExecStart=/usr/sbin/keepalived --dont-fork $KEEPALIVED_OPTIO>
Main PID: 9466 (code=exited, status=0/SUCCESS)
CPU: 3.975s
Dec 12 23:05:49 proxy1 systemd[1]: Stopping LVS and VRRP High Availability Mon>
Dec 12 23:05:49 proxy1 Keepalived[9466]: Stopping
Dec 12 23:05:49 proxy1 Keepalived_vrrp[9467]: (VI_1) sent 0 priority
Dec 12 23:05:49 proxy1 Keepalived_vrrp[9467]: (VI_1) removing VIPs.
Dec 12 23:05:50 proxy1 Keepalived_vrrp[9467]: Stopped - used (self/children) 0>
Dec 12 23:05:50 proxy1 Keepalived[9466]: CPU usage (self/children) user: 0.004>
Dec 12 23:05:50 proxy1 Keepalived[9466]: Stopped Keepalived v2.2.8 (04/04,2023>
Dec 12 23:05:50 proxy1 systemd[1]: keepalived.service: Deactivated successfull>
Dec 12 23:05:50 proxy1 systemd[1]: Stopped LVS and VRRP High Availability Moni>
Dec 12 23:05:50 proxy1 systemd[1]: keepalived.service: Consumed 3.975s CPU tim>
[root@proxy1 ~]#
在备机检查服务状态,发现VIP已经漂移到备机上了
[root@proxy2 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Fri 2025-12-12 22:00:51 CST; 1h 5min ago
Main PID: 9283 (nginx)
Tasks: 3 (limit: 22927)
Memory: 7.6M
CPU: 91ms
CGroup: /system.slice/nginx.service
├─9283 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
├─9373 "nginx: worker process"
└─9374 "nginx: worker process"
Dec 12 22:00:51 proxy2 systemd[1]: Starting Nginx Web Server...
Dec 12 22:00:51 proxy2 systemd[1]: Started Nginx Web Server.
[root@proxy2 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: active (running) since Fri 2025-12-12 22:58:42 CST; 7min ago
Main PID: 9378 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 5.1M
CPU: 4.313s
CGroup: /system.slice/keepalived.service
├─9378 /usr/sbin/keepalived --dont-fork -D
└─9379 /usr/sbin/keepalived --dont-fork -D
Dec 12 23:05:49 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:49 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:49 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:49 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: (VI_1) Sending/queueing gratuito>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 55649 bytes 71742448 (68.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 17794 bytes 3303425 (3.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]#

CRMEB商城业务不受影响!
抢修主机,发现VIP又漂移到主机上了
[root@proxy1 ~]# systemctl start nginx
[root@proxy1 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Fri 2025-12-12 23:08:18 CST; 3s ago
Process: 10417 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, st>
Process: 10419 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/c>
Main PID: 10420 (nginx)
Tasks: 3 (limit: 22927)
Memory: 2.9M
CPU: 15ms
CGroup: /system.slice/nginx.service
├─10420 "nginx: master process /usr/local/nginx/sbin/nginx -c /us>
├─10421 "nginx: worker process"
└─10422 "nginx: worker process"
Dec 12 23:08:18 proxy1 systemd[1]: Starting Nginx Web Server...
Dec 12 23:08:18 proxy1 systemd[1]: Started Nginx Web Server.
[root@proxy1 ~]# systemctl start keepalived
[root@proxy1 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: active (running) since Fri 2025-12-12 23:08:27 CST; 4s ago
Main PID: 10427 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 2.2M
CPU: 61ms
CGroup: /system.slice/keepalived.service
├─10427 /usr/sbin/keepalived --dont-fork -D
└─10428 /usr/sbin/keepalived --dont-fork -D
Dec 12 23:08:29 proxy1 Keepalived_vrrp[10428]: (VI_1) received lower priority >
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: (VI_1) Receive advertisement ti>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: (VI_1) Entering MASTER STATE
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: (VI_1) setting VIPs.
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: (VI_1) Sending/queueing gratuit>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: Sending gratuitous ARP on ens16>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: Sending gratuitous ARP on ens16>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: Sending gratuitous ARP on ens16>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: Sending gratuitous ARP on ens16>
Dec 12 23:08:30 proxy1 Keepalived_vrrp[10428]: Sending gratuitous ARP on ens16>
[root@proxy1 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.102 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
RX packets 56169 bytes 74237055 (70.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27920 bytes 6356664 (6.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.200 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:50:56:3e:be:ee txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 2 bytes 168 (168.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 168 (168.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy1 ~]#
备机已释放VIP
[root@proxy2 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Fri 2025-12-12 22:00:51 CST; 1h 8min ago
Main PID: 9283 (nginx)
Tasks: 3 (limit: 22927)
Memory: 7.6M
CPU: 91ms
CGroup: /system.slice/nginx.service
├─9283 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
├─9373 "nginx: worker process"
└─9374 "nginx: worker process"
Dec 12 22:00:51 proxy2 systemd[1]: Starting Nginx Web Server...
Dec 12 22:00:51 proxy2 systemd[1]: Started Nginx Web Server.
[root@proxy2 ~]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; pres>
Active: active (running) since Fri 2025-12-12 22:58:42 CST; 10min ago
Main PID: 9378 (keepalived)
Tasks: 2 (limit: 22927)
Memory: 5.1M
CPU: 6.171s
CGroup: /system.slice/keepalived.service
├─9378 /usr/sbin/keepalived --dont-fork -D
└─9379 /usr/sbin/keepalived --dont-fork -D
Dec 12 23:05:49 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: (VI_1) Sending/queueing gratuito>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:05:54 proxy2 Keepalived_vrrp[9379]: Sending gratuitous ARP on ens160>
Dec 12 23:08:30 proxy2 Keepalived_vrrp[9379]: (VI_1) Master received advert fr>
Dec 12 23:08:30 proxy2 Keepalived_vrrp[9379]: (VI_1) Entering BACKUP STATE
Dec 12 23:08:30 proxy2 Keepalived_vrrp[9379]: (VI_1) removing VIPs.
[root@proxy2 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 55792 bytes 71753169 (68.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 18009 bytes 3320995 (3.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@proxy2 ~]#

CRMEB商城业务不受影响!
拓展测试
对接同一个教室里的 Web 服务
[root@proxy1 nginx]# vim nginx.conf
[root@proxy1 nginx]# cat nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.11.29:80 max_fails=2 fail_timeout=3s;
server 192.168.11.187:80 max_fails=2 fail_timeout=3s;
server 192.168.11.198:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
[root@proxy1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy1 nginx]# nginx -s reload
[root@proxy2 nginx]# vim nginx.conf
[root@proxy2 nginx]# cat nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.11.29:80 max_fails=2 fail_timeout=3s;
server 192.168.11.187:80 max_fails=2 fail_timeout=3s;
server 192.168.11.198:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
[root@proxy2 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy2 nginx]# nginx -s reload







iptables网络代理转发
[root@proxy1 nginx]# vim nginx.conf
[root@proxy1 nginx]# cat nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.88.103:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
[root@proxy1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy1 nginx]# nginx -s reload
[root@proxy2 nginx]# cat nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream web_pool {
server 192.168.88.103:80 max_fails=2 fail_timeout=3s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
[root@proxy2 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy2 nginx]# nginx -s reload
[root@server3 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.103 netmask 255.255.255.0 broadcast 192.168.88.255
ether 00:50:56:36:7d:75 txqueuelen 1000 (Ethernet)
RX packets 91554 bytes 93244053 (88.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 53207 bytes 17528569 (16.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens224: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.11.60 netmask 255.255.255.0 broadcast 192.168.11.255
ether 00:0c:29:e6:d9:8a txqueuelen 1000 (Ethernet)
RX packets 41754 bytes 10073211 (9.6 MiB)
RX errors 0 dropped 893 overruns 0 frame 0
TX packets 3890 bytes 411878 (402.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 72 bytes 24386 (23.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 72 bytes 24386 (23.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@server3 ~]#
echo 1 > /proc/sys/net/ipv4/ip_forward
sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
sysctl -p
iptables -t nat -F
iptables -t nat -A PREROUTING -d 192.168.88.103 -p tcp --dport 80 -j DNAT --to-destination 192.168.11.29:80
iptables -t nat -A POSTROUTING -d 192.168.11.29 -p tcp --dport 80 -j SNAT --to-source 192.168.11.60
iptables -A FORWARD -j ACCEPT
[root@server3 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere server3 tcp dpt:http to:192.168.11.29:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT tcp -- anywhere 192.168.11.29 tcp dpt:http to:192.168.11.60
[root@server3 ~]#


经典 iptables NAT 实战

echo 1 > /proc/sys/net/ipv4/ip_forward
sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
sysctl -p
iptables -t nat -F
iptables -t nat -A PREROUTING -d 192.168.88.100 -p tcp --dport 80 -j DNAT --to-destination 192.168.19.99:80
iptables -t nat -A POSTROUTING -d 192.168.19.99 -p tcp --dport 80 -j SNAT --to-source 192.168.88.100
iptables -A FORWARD -j ACCEPT



常用排错命令
journalctl -u keepalived -f # 实时看漂移日志
ss -lnt | grep :80 # 确认本机 80 监听
ip a show ens160 # 看 VIP 在哪台
systemctl status nginx keepalived
至此,“nginx+keepalived” 高可用 就完整落地了!
- 硬件故障 → VIP 漂
- nginx 服务故障 → 检测脚本立即降权/自杀 → VIP 漂
- 用户始终通过域名/VIP 访问,后端真实 Web 服务器对客户端完全透明。
Keepalived 的配置补充(了解)
非抢占模式
为了提升用户访问体验,避免因 **VIP(虚拟 IP)**频繁切换导致的服务短暂不可用或 HTTP 请求异常,我们采用 非抢占式(nopreempt)模式 来控制 VIP 的归属,确保 VIP 不会因节点恢复而发生不必要的切换。
第一步:在 vrrp_instance 块下两个节点各增加了 nopreempt 指令,表示不争抢 VIP
vrrp_instance VI_1 {
virtual_router_id 51
nopreempt
priority 100
}
第二步:节点的state都为BACKUP
vrrp_instance VI_1 {
state BACKUP
}
两个keepalived节点都启动后,默认都是BACKUP状态,双方在发送组播信息后,会根据优先级来选举一个MASTER出来。由于两者都配置了nopreempt,所以MASTER从故障中恢复后,不会抢占vip。这样会避免VIP切换可能造成的服务延迟。
非抢占模式,就是为了用户体验更加。服务恢复服务之后,不要抢占VIP。
nopreempt
empt 在拉丁文中是“拿走”的意思。
pre 表示“预先的,提前的”。比如 prepare 准备,preview 预览;
preempt 表示“提前拿走,抢占”。nopreempt 表示 “非抢占”。
VIP 脑裂
脑裂(split-brain):指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。(MASTER-BACKUP,两台机器上同时拥有VIP)
主要原因:
1、网络通信故障;
2、防火墙未关闭或防火墙规则配置不正确;
查看日志:
# tail -f /var/log/messages
使用tcpdump抓取vrrp数据包:
# yum install tcpdump -y
# tcpdump -i ens160 vrrp -n
-i:interface 指定网卡
-n:number 以数字形式显示IP地址
VIP所在主机 => 发送vrrp数据包 => 组播地址 => 224.0.0.18

防火墙配置:
# 允许VRRP协议
firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
# 添加组播地址
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="224.0.0.18" accept'
# 允许Keepalived服务
firewall-cmd --permanent --add-service=high-availability
# 重新加载防火墙
firewall-cmd --reload
firewall-cmd命令
--permanent:永久
--add-rich-rule:添加防火墙规则
rule family="ipv4" destination address="224.0.0.18" accept:针对组播地址224.0.0.18
--add-service:根据名称设置防火墙规则,high-availability防火墙预定服务名,是包括keepalived在内的所有高可用软件统称
--add-port:根据端口号设置防火墙规则
firewall-cmd --reload:刷新防火墙,让规则立即生效
总结
什么是脑裂?
答:在一个集群中,可能出现两个VIP
产生脑裂根本原因?
答:集群中的各个节点可能由于网络通信故障导致连接不上主节点
脑裂影响?
答:因为有两个VIP,所有请求会出现争抢情况,严重可能会造成数据损坏!
解决方案:
恢复网络通信(防火墙、SELinux、配置文件)
单播模式
广播 > 组播 > 单播
广播:类似屏幕广播,把信息发送广播地址(本网段的.255)
组播:范围略小于广播,只有同组节点才能收到组播信息(keepalived默认情况 => 224.0.0.18)
单播:范围最小,仅局限于点对点传输信息(master => backup)
一方面,keepalived在组播模式下所有的信息都会向224.0.0.18的组播地址发送,产生众多的无用信息,并且会产生干扰和冲突。另一方面,在某些特定环境(云服务器)禁止了组播方式,造成没办法获取到MASTER的数据包信息。
所以需要将其组播的模式改为单播。这是一种安全的方法,避免局域网内有大量的keepalived造成虚拟路由id的冲突(VIP脑裂)。 单播模式需要关闭vrrp_strict这个选项。单播需要在VIP实例配置段加入单播的源地址和目标地址
单播模式的配置,是需要在keepalived1.2.10(含)以上版本
vrrp_instance VI_1 {
unicast_src_ip 192.168.88.128 ##(本地IP地址)
unicast_peer {
192.168.88.129 ##(对端IP地址)此地址一定不能忘记,支持多台机器
}
}
注:
针对于web01 unicast_src_ip 就是192.168.88.101 unicast_peer 192.168.88.103
针对于web02 unicast_src_ip 就是192.168.88.103 unicast_peer 192.168.88.101
第一步:需要使用高一点版本的keepalived(1.2.11)
# cd /root/soft
# tar xvf keepalived-1.2.11.tar.gz
# cd keepalived-1.2.11
# ./configure --prefix=/usr/local/keepalived
# make && make install
第二步:查看目录,配置文件和启动文件
注意如果使用的是1.3以上版本的话,注意注释模式:
删除vrrp_strict
# /usr/local/keepalived/sbin/keepalived -f /usr/local/keepalived/etc/keepalived/keepalived.conf -D
master:keepalived.conf
vrrp_instance VI_1 {
unicast_src_ip 192.168.88.101
unicast_peer {
192.168.88.103
}
}
注:
针对于web01 unicast_src_ip 就是192.168.88.101 unicast_peer 192.168.88.103
针对于web02 unicast_src_ip 就是192.168.88.103 unicast_peer 192.168.88.101
backup:keepalived.conf
vrrp_instance VI_1 {
unicast_src_ip 192.168.88.103
unicast_peer {
192.168.88.101
}
}
注:
针对于web01 unicast_src_ip 就是192.168.88.101 unicast_peer 192.168.88.103
针对于web02 unicast_src_ip 就是192.168.88.103 unicast_peer 192.168.88.101
裂:vip出现在了多台机器上。网络不通畅,禁用了数据包,主备服务器没法通讯,造成备服务器认为主服务器不可用,绑定VIP,主服务器VIP不会释放。
① 双备或者多备模式 BACKUP 通过priority权重来区分谁的优先级更高
② 单播的方式
③ 时间不同步 服务器时间校时
删库跑路?



备份:
mkdir /backup
mysqldump -uroot -pMySQL@666 --all-databases --single-transaction --routines --triggers --events > /backup/all_$(date +%Y%m%d_%H%M%S).sql
mysqldump \
-uroot \ # 指定用户名
-pMySQL@666 \ # 指定密码
--all-databases \ # 备份所有数据库(含建库语句)
--single-transaction \ # 开启事务快照,备份期间不锁表
--routines \ # 备份存储过程和函数
--triggers \ # 备份触发器
--events \ # 备份事件调度器
> /backup/all_$(date +%Y%m%d_%H%M%S).sql # 输出到带时间戳的文件



恢复:
mysql -uroot -pMySQL@666 < /backup/all_20260526_164149.sql

后端 MySQL 的主从架构升级(拓展)
主从同步(复制)原理 :
主服务器开启bin-log(记录了写操作) 从服务器获取到主服务器的bin-log 记录到relay-log中
从服务器在通过异步的线程方式,对于relay-log进行重放操作
IO线程去主服务器binlog日志拷贝 => 写入到从服务器的relay log中
SQL线程根据relay log变化,自动去执行拷贝过来DML语句,重演
主服务器: bin-log
从服务器: relay-log
DML => MASTER SQL => binlog日志中
SLAVE SQL => 监听MASTER binlog日志变化,一旦监测到主服务器发生变化 => 通过网络IO线程复制到SLAVE从服务器中,放入relaylog中继日志 => SLAVE使用SQL线程重演MASTER SQL操作
从库 MySQL 安装
上传安装脚本和软件包从库服务器
[root@slave ~]# cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/export/server/mysql
datadir=/export/server/mysql/data
socket=/tmp/mysql.sock
port=3306
log-error=/export/server/mysql/slave.err
log-bin=/export/server/mysql/data/binlog
relay-log=/export/server/mysql/data/relaylog
server-id=20
character_set_server=utf8mb4
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=1
read-only=on
EOF
[root@slave ~]# systemctl restart mysqld
[root@slave ~]# systemctl status mysqld --no-pager
修改 MySQL 配置
主库停止服务
[root@master ~]# systemctl stop mysqld # 可选
[root@master ~]# cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/export/server/mysql
datadir=/export/server/mysql/data
socket=/tmp/mysql.sock
sql_mode=NO_ENGINE_SUBSTITUTION
port=3306
log-error=/export/server/mysql/master.err
log-bin=/export/server/mysql/data/binlog
server-id=10
character_set_server=utf8mb4
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=1
EOF
[root@master ~]# systemctl restart mysqld
[root@master ~]# systemctl status mysqld --no-pager
数据同步
逻辑导出(适合中小型库)
# 主库执行
[root@master ~]# mysqldump -u root -p --all-databases --single-transaction --master-data=2 --set-gtid-purged=ON > /tmp/full.sql
解释说明:
# MySQL 主库全量一致性热备份(主从复制专用)
mysqldump \
-u root \ # 指定MySQL登录用户 root
-p \ # 提示输入密码,不显示明文
--all-databases \ # 备份所有数据库
--single-transaction \ # InnoDB 一致性热备份,不锁表、不影响业务
--master-data=2 \ # 【关键】将binlog位置写入备份文件
# =1:会生成可执行的 CHANGE MASTER TO 语句(导入时自动执行)
# =2:会生成注释形式的 CHANGE MASTER TO 语句(仅记录、不自动执行,更安全)
--set-gtid-purged=ON \ # 记录GTID事务号,主从自动识别同步起点
> /tmp/full.sql # 备份输出到 /tmp/full.sql
# 拷贝到从库
[root@master ~]# scp /tmp/full.sql root@192.168.88.133:/tmp/
# 从库执行
[root@slave ~]# mysql -u root -pMySQL@666 < /tmp/full.sql
主库授权
[root@master ~]# systemctl start mysqld
[root@master ~]# mysql -u root -pMySQL@666
mysql> CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY 'MySQL@666';
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
mysql> flush privileges;
从库 Slave 服务器进行主从同步
[root@slave ~]# systemctl start mysqld
[root@slave ~]# mysql -uroot -pMySQL@666
mysql> change replication source to
source_host='192.168.88.101',
source_port=3306,
source_user='slave',
source_password='MySQL@666',
source_auto_position=1;
mysql> start replica;
mysql> show slave status\G





拓展:更改数据库地址



