基于 Maven 构建 + 阿里云镜像优化
一、架构说明(兼容原双主双从)
| 角色 | IP | 部署内容 |
|---|---|---|
| 数据库服务器 | 172.25.254.99 | MariaDB |
| 应用服务器 1 | 172.25.254.100 | ZrLog(Maven 构建 Jar)+ JDK11 |
| 应用服务器 2 | 172.25.254.200 | ZrLog(Maven 构建 Jar)+ JDK11 |
| HAProxy Master1 | 172.25.254.10 | HAProxy + Keepalived + 邮件 |
| HAProxy Master2 | 172.25.254.20 | HAProxy + Keepalived + 邮件 |
| VIP1 | 172.25.254.101 | Keepalived 虚拟 IP |
| VIP2 | 172.25.254.102 | Keepalived 虚拟 IP |
二、基础环境优化(所有机器)
2.1 替换阿里云 YUM 源(替代本地光盘,更通用)
]# mount /dev/sr0 /mnt
mount: /mnt: WARNING: source write-protected, mounted read-only.
]# cat /etc/yum.repos.d/
redhat.repo x.repo
]# cat /etc/yum.repos.d/x.repo
[base01]
name=base
baseurl=/mnt/BaseOS
enable=1
gpgcheck=0
[base02]
name=app
baseurl=/mnt/AppStream
enable=1
gpgcheck=0
2.2 安装基础依赖(所有机器)
]# yum install -y tree vim wget net-tools zip
三、部署 MariaDB(192.168.223.22)
# 安装MariaDB(阿里云源)
dnf install -y mariadb-server
# 启动并设置开机自启
systemctl start mariadb && systemctl enable mariadb
# 初始化数据库并配置ZrLog权限
mysql -u root -e "
CREATE DATABASE IF NOT EXISTS zrlog DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'zrlog'@'%' IDENTIFIED BY 'zrlog123456';
GRANT ALL PRIVILEGES ON zrlog.* TO 'zrlog'@'%';
FLUSH PRIVILEGES;
"
# 开放数据库端口(可选)如果已经关闭防火墙就无需操作下面两条指令
firewall-cmd --add-port=3306/tcp --permanent
firewall-cmd --reload
四、部署 ZrLog 应用服务器
4.1 安装 JDK + Maven(配置阿里云镜像)
# 安装JDK 11
# 1. 上传 jdk-11.tar.gz 到 /root 目录,执行解压
cd /root
tar -zxf jdk-11_linux-x64_bin.tar.gz
mv jdk-11 jdk11
# 2. 配置全局环境变量(永久生效)
cat > /etc/profile.d/jdk.sh << 'EOF'
export JAVA_HOME=/root/jdk11
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib
EOF
# 3. 生效并验证
source /etc/profile.d/jdk.sh
java -version # 输出JDK版本即成功
# 1. 下载 Maven 3.9.6(适配JDK 11)
cd /root
wget https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
# 2. 解压并重命名
root@zrlog ~]# tar -zxf apache-maven-3.9.14-bin.tar.gz
[root@zrlog ~]# mv apache-maven-3.9.14 maven
# 3. 配置全局环境变量
cat > /etc/profile.d/maven.sh << 'EOF'
export MAVEN_HOME=/root/maven
export PATH=$MAVEN_HOME/bin:$PATH
EOF
source /etc/profile.d/maven.sh
mvn -version # 输出Maven版本即成功
[root@zrlog package]# vim /root/maven/conf/settings.xml
.....
<mirror>
<id>tencentmaven</id>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/public/</url>
</mirror>
....
4.2 下载 ZrLog 源码并通过 Maven 构建
cd /root
# 解压到指定目录,避免文件混乱
unzip -q zrlog-3.3.0-1811fd7-release.zip -d zrlog-src
cd zrlog-src
# 进入pom.xml所在目录(根据你的压缩包结构)
[root@dev ~]# find /root/zrlog-src/ -name pom.xml
/root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml
# 配置阿里云镜像(解决依赖下载慢/失败)
mv /root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml /root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml.bak
# 写入全新的独立pom.xml(无需父POM,直接构建War包)
cat > /root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 手动定义项目基本信息(替代父POM) -->
<groupId>com.hibegin</groupId>
<artifactId>zrlog-web</artifactId>
<version>3.3.0</version>
<packaging>war</packaging>
<name>ZrLog Web</name>
<description>ZrLog Blog System</description>
<!-- 核心依赖(覆盖父POM的关键依赖) -->
<dependencies>
<!-- Servlet & JSP 核心 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<!-- Java EE 基础 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 数据库驱动(ZrLog核心依赖) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.13</version>
</dependency>
</dependencies>
<!-- 构建配置(确保能打出可运行的War包) -->
<build>
<finalName>zrlog</finalName>
<plugins>
<!-- 编译插件(适配JDK11) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- War包插件(忽略缺失web.xml) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- 指向ZrLog的源码/资源目录(关键) -->
<webResources>
<resource>
<directory>/root/zrlog-src</directory>
<includes>
<include>WEB-INF/**/*</include>
<include>META-INF/**/*</include>
<include>**/*.jsp</include>
<include>**/*.html</include>
<include>**/*.css</include>
<include>**/*.js</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
EOF
[root@dev ~]# cd /root/zrlog-src/META-INF/maven/com.hibegin/package/
# 执行Maven打包(-DskipTests跳过测试,加快构建速度)
mvn clean package -DskipTests
4.1 复制 War 包并清理旧数据
[root@zrlog-node2 ~]# tar -xaf apache-tomcat-10.1.52.tar.gz
[root@zrlog-node2 ~]# mv apache-tomcat-10.1.52 tomcat10
# 复制War包到Tomcat webapps目录,重命名为ROOT.war(直接访问根路径)
[root@zrlog-node2 ~]# cd /root/zrlog-src/META-INF/maven/com.hibegin/package/
[root@zrlog-node2 package]# cp target/zrlog.war /root/tomcat10/webapps/ROOT.war
# 清理Tomcat旧解压文件(避免冲突)
rm -rf /root/tomcat10/webapps/ROOT
4.2 启动 Tomcat 并验证
# 启动Tomcat
/root/tomcat10/bin/startup.sh
# 查看启动日志(确认War包解压、服务无报错)
tail -f /root/tomcat10/logs/catalina.out
✅ 启动成功标识:
日志中出现 Server startup in XXX ms,且无 ERROR 级日志。
在浏览器输出:

五、HAProxy + Keepalived 适配调整(20/23 服务器)
5.1 调整 HAProxy 配置
]# yum install haproxy -y
cat > /etc/haproxy/haproxy.cfg << 'EOF'
# global 段:全局配置(进程级参数)
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
# defaults 段:为后续的 frontend/backend 设置默认参数,避免重复配置。
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
# listen stats 段:监控页面(可选)
# 提供可视化监控界面,查看后端节点健康状态、连接数等。
listen stats
bind *:8080
mode http
stats enable
stats uri /haproxy-stats
stats auth admin:admin123
#frontend http-in 段:定义 HAProxy 接收请求的端口和转发规则。
frontend http-in
bind *:80 # 监听80端口(客户端访问的入口)
default_backend zrlog_servers # 所有请求默认转发到zrlog_servers后端
#backend zrlog_servers 段:定义后端服务器列表、负载均衡算法、健康检查规则。
#check:启用健康检查;inter 2000:每 2 秒检查一次;rise 2:连续 2 次健康则标记为可用;fall 3:连续 3 次失败则标记为不可用。
backend zrlog_servers
balance roundrobin # 负载均衡策略
# 关键1:调整健康检查规则,匹配后端实际响应
option httpchk GET / HTTP/1.1\r\nHost:\ zrlog.example.com # 模拟带Host的请求(替换为你的ZrLog域名/IP)
http-check expect status 200 # 若后端返回302,改为 http-check expect status 302
# 关键2:放宽健康检查参数,避免误判
server zrlog1 172.25.254.100:8080 check inter 5s fall 3 rise 2 # 检查间隔5s,3次失败才标记DOWN
server zrlog2 172.25.254.200:8080 check inter 5s fall 3 rise 2
# 关键3:转发关键请求头(ZrLog可能依赖)
http-request set-header X-Real-IP %[src]
http-request set-header X-Forwarded-For %[src]
EOF
# 重启HAProxy
systemctl restart haproxy && systemctl enable haproxy
]# haproxy -c -f /etc/haproxy/haproxy.cfg
5.2 Keepalived 配置(无变更,复用原双主配置)
创建 Shell 邮件发送脚本
# RHEL 9.3/CentOS Stream 9/OpenEuler
]# yum install s-nail -y
]# chmod 755 /etc/s-nail.rc
# 编辑 mailx 主配置文件
]# vim /etc/s-nail.rc
# 在文件末尾添加以下内容(替换为你的 QQ 邮箱信息)
set from="@qq.com" # 发件人邮箱
set smtp="smtps://smtp.qq.com:465" # QQ 邮箱 SMTP 地址+端口
set smtp-auth-user="@qq.com" # 邮箱账号
set smtp-auth-password="你的QQ邮箱授权码" # 替换为新生成的授权码(关键!)
set smtp-auth=login # 认证方式
set ssl-verify=ignore # 忽略 SSL 验证(避免版本问题)
set nss-config-dir=/etc/pki/nssdb/ # SSL 证书路径(系统默认)
# 执行以下命令,测试基础发送
echo "这是 Keepalived 邮件通知测试内容" | mailx -s "测试邮件" @qq.com
5.4 创建 Keepalived 通知脚本
cat > /usr/local/bin/keepalived_notify.sh << 'EOF'
#!/bin/bash
# Keepalived 状态变更邮件通知脚本
# 参数:$1 = 状态(master/backup/fault)
# 配置参数
VIP="172.25.254.101" # 你的 VIP 地址
TO_EMAIL="1341101176@qq.com" # 收件邮箱
SUBJECT="【Keepalived 告警】节点状态变更"
# 拼接邮件内容
MESSAGE="
=====================================
Keepalived 节点状态变更通知
=====================================
节点状态:$1
VIP 地址:${VIP}
发生时间:$(date +'%Y-%m-%d %H:%M:%S')
=====================================
"
# 用 mailx 发送邮件
echo "${MESSAGE}" | mailx -s "${SUBJECT}" ${TO_EMAIL}
# 记录日志(可选,便于排查)
echo "$(date +'%Y-%m-%d %H:%M:%S') - 发送 Keepalived 状态邮件,状态:$1" >> /var/log/keepalived_mail.log
EOF
# 赋予执行权限
chmod +x /usr/local/bin/keepalived_notify.sh
###
# 172.25.254.10 配置(同原文档)
]# yum install keepalived -y
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id LVS_10 # 全局标识:当前Keepalived节点的唯一名称(自定义,建议含IP/主机名)
}
vrrp_instance VI_1 { # 定义第一个VRRP实例(对应VIP1:172.25.254.)
state MASTER # 初始状态:MASTER(主节点),但最终由priority决定实际角色
interface ens160 # 绑定的网卡(必须和服务器实际网卡名一致,如ens33/eth0)
virtual_router_id 51 # VRRP组ID(范围1-255):同一VIP的实例ID必须相同(20和23节点的VI_1都为51)
priority 100 # 优先级(0-255):数值越高越优先成为Master,20节点VI_1优先级100 > 23节点的90
advert_int 1 # VRRP通告间隔:1秒(节点间每秒发送一次心跳,确认对方存活)
authentication { # 认证配置:防止非法节点加入VRRP组
auth_type PASS # 认证类型:PASS(密码认证,另一种是AH,较少用)
auth_pass 1111 # 认证密码:同一VRRP组(VI_1)的节点密码必须相同(20和23节点都为1111)
}
virtual_ipaddress { # 该实例对应的VIP列表(可配置多个,空格分隔)
172.25.254.101 # 核心:虚拟IP,客户端访问的入口
}
# 状态变化触发的脚本(自定义告警脚本,路径需存在且可执行)
notify_master "/usr/local/bin/keepalived_notify.sh master" # 成为Master时执行
notify_backup "/usr/local/bin/keepalived_notify.sh backup" # 成为Backup时执行
notify_fault "/usr/local/bin/keepalived_notify.sh fault" # 故障(如网卡宕机)时执行
}
vrrp_instance VI_2 { # 定义第二个VRRP实例(对应VIP2:192.168.223.101)
state BACKUP # 初始状态:BACKUP(备节点)
interface ens160 # 绑定同一块网卡(和VI_1一致)
virtual_router_id 52 # VRRP组ID:VI_2的ID为52(和VI_1不同,避免冲突)
priority 90 # 优先级:90 < 23节点VI_2的100,因此23节点是VI_2的Master
advert_int 1 # 心跳间隔:1秒(和VI_1一致即可)
authentication {
auth_type PASS
auth_pass 2222 # VI_2的认证密码(和VI_1不同,也可相同,建议区分)
}
virtual_ipaddress {
1172.25.254.101 # 第二个VIP
}
# 状态变化脚本(和VI_1共用同一个脚本,通过参数区分状态)
notify_master "/usr/local/bin/keepalived_notify.sh master"
notify_backup "/usr/local/bin/keepalived_notify.sh backup"
notify_fault "/usr/local/bin/keepalived_notify.sh fault"
}
EOF
# 172.25.254.20 配置(同原文档)
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id LVS_23 # 节点唯一标识(和20节点区分,如LVS_23)
}
vrrp_instance VI_1 { # 对应20节点的VI_1(VIP1:100)
state BACKUP # 初始状态:BACKUP(备节点)
interface ens160 # 网卡名必须和20节点一致
virtual_router_id 51 # VRRP组ID:必须和20节点VI_1的51一致,否则无法组成同一组
priority 90 # 优先级:90 < 20节点的100,因此20节点是VI_1的Master
advert_int 1 # 心跳间隔:和20节点一致(1秒)
authentication {
auth_type PASS
auth_pass 1111 # 认证密码:必须和20节点VI_1的1111一致,否则认证失败
}
virtual_ipaddress {
172.25.254.101 # 同一VIP:100(和20节点VI_1一致)
}
# 状态脚本(和20节点路径一致,需确保脚本在23节点也存在)
notify_master "/usr/local/bin/keepalived_notify.sh master"
notify_backup "/usr/local/bin/keepalived_notify.sh backup"
notify_fault "/usr/local/bin/keepalived_notify.sh fault"
}
vrrp_instance VI_2 { # 对应20节点的VI_2(VIP2:101)
state MASTER # 初始状态:MASTER(主节点)
interface ens160
virtual_router_id 52 # VRRP组ID:必须和20节点VI_2的52一致
priority 100 # 优先级:100 > 20节点的90,因此23节点是VI_2的Master
advert_int 1
authentication {
auth_type PASS
auth_pass 2222 # 认证密码:必须和20节点VI_2的2222一致
}
virtual_ipaddress {
172.25.254.102 # 同一VIP:101
}
# 状态脚本
notify_master "/usr/local/bin/keepalived_notify.sh master"
notify_backup "/usr/local/bin/keepalived_notify.sh backup"
notify_fault "/usr/local/bin/keepalived_notify.sh fault"
}
EOF
# 重启Keepalived
systemctl restart keepalived && systemctl enable keepalived
关键配置行的核心规则(必记)
| 配置项 | 核心规则 |
|---|---|
virtual_router_id |
同一 VIP 的 VRRP 实例 ID 必须相同(如 VI_1 的 51),不同 VIP 的 ID 必须不同(如 VI_2 的 52) |
priority |
优先级决定最终 Master 角色,数值越高越优先(初始 state 仅为参考) |
auth_pass |
同一 VRRP 实例的节点密码必须一致(如 VI_1 的 1111),否则无法加入组 |
interface |
必须绑定服务器实际存在的网卡(可通过ip addr查看),否则 VIP 无法挂载 |
virtual_ipaddress |
同一 VRRP 实例的 VIP 必须一致,是客户端访问的核心入口 |
advert_int |
同一组的节点心跳间隔必须一致(建议 1 秒),否则会判定对方故障 |
六、验证与访问
6.1 基础验证
# 检查HAProxy后端健康状态
curl http://172.25.254.10:8080/haproxy-stats # 账号admin/密码admin123
# 检查VIP是否生效
ip addr show | grep 172.25.254.101
ip addr show | grep 172.25.254.102
# 测试VIP访问
curl -I http://172.25.254.101/
curl -I http://172.25.254.102/
HAProxy 监控页面全解析(从图中能看出的核心信息)
这是 HAProxy 2.4.22 版本的负载均衡状态监控页,能直观看到 HAProxy 进程状态、前端监听、后端服务器健康状态、流量 / 错误等核心信息,下面分模块拆解:
一、General process information(全局进程信息)
这部分是 HAProxy 服务本身的运行状态:
进程基本信息
pid = 12284:HAProxy 进程 ID 正常,进程数nbproc = 1(单进程模式,符合配置),线程数nbthread = 2;
uptime = 0d 0h02m11s:HAProxy 已启动 2 分 11 秒,服务正常运行;
Running tasks: 0/15; idle = 100 %:当前无运行中任务,空闲率 100%,说明无业务请求压力。系统资源限制
maxconn = 4000:全局最大并发连接数(和你配置的global段maxconn 4000一致);
current conns = 1:当前仅 1 个连接(就是你访问监控页的连接),无业务连接;
conn rate = 1/sec:连接速率 1 次 / 秒,bit rate = 0.000 kbps:当前无业务流量。状态色标说明
绿色 =
active UP(正常在线),红色 =active or backup DOWN(故障离线),黄色 = 过渡状态;图中后端
zrlog1/zrlog2为红色,说明两台后端 ZrLog 服务器全部处于 DOWN 状态。
二、stats 监听段(监控页自身的前端)
这是你访问的
8080/haproxy-stats监控端口的状态:
Frontend(前端)
Status: OPEN:监控端口正常监听,可正常访问;
Sessions: Cur=1:当前 1 个连接(你的浏览器访问),Total=3:累计 3 次连接;
Bytes In=461 / Out=263:监控页的请求 / 响应字节数,无业务流量。Backend(后端)
Status: 2m11s UP:后端状态正常,和 HAProxy 启动时间一致;
LastChk: 2m11s UP:最后一次健康检查正常,监控服务自身无故障。
三、http-in 前端段(业务 80 端口监听)
这是你配置的
frontend http-in(监听 80 端口,业务入口)的状态:
Frontend 状态
Status: OPEN:80 端口正常监听,可接收客户端请求;
Sessions: Cur=0, Max=1, Total=1:当前无业务连接,累计 1 次连接(测试访问);
Errors: Req=1:有 1 次请求错误(因为后端服务器全 DOWN,请求转发失败)。
四、zrlog_servers 后端段(核心业务后端,关键问题所在)
这是你配置的
backend zrlog_servers(ZrLog 应用服务器池)的状态,核心问题一目了然:1. 后端服务器状态(最关键)
服务器 状态 健康检查结果 核心问题 zrlog1(172.25.254.10:9090)2m11s DOWNL4CON in 0ms第 4 层连接失败(HAProxy 连不上 9090 端口,服务器 / 服务宕机) zrlog2(172.25.254.20:9090)2m10s DOWNL4CON in 0ms同样 L4 层连接失败,两台后端全部离线 2. 关键指标解读
Status: 2m10s DOWN:两台服务器从 HAProxy 启动后就一直处于 DOWN 状态,从未正常上线;
LastChk: L4CON in 0ms:健康检查是第 4 层(TCP 层)连接检查,0ms 超时说明 HAProxy 根本连不上 9090 端口,直接拒绝连接;
Dwn: 1 / Dwntme: 2m11s:服务器故障次数 1 次,故障时长 2 分 11 秒(和 HAProxy 启动时间一致);
Backend 总状态: 2m10s DOWN:因为两台后端全 DOWN,整个后端服务器池状态为 DOWN,业务完全不可用。
五、从页面能直接得出的结论(核心)
HAProxy 服务本身正常:进程运行、80/8080 端口正常监听,监控页可正常访问;
两台 ZrLog 应用服务器(172.25.254.100/24:9090)全部故障离线:HAProxy 无法连接到后端 9090 端口,业务完全不可用;
故障原因定位:
L4CON in 0ms是 TCP 层连接失败,说明:
要么 100/200服务器的 9090 端口未监听(ZrLog/Tomcat 服务未启动 / 端口错);
要么服务器防火墙 / 网络拦截了 9090 端口,HAProxy 无法连通;
要么服务器本身宕机 / 网络不通。
当前无业务流量:所有连接数、流量指标均为 0,仅监控页自身有连接。
六、下一步排查步骤(对应页面问题)
检查后端服务器服务状态 :在 21/24 节点执行
ss -tnlp | grep 9090,确认 9090 端口是否被 ZrLog/Tomcat 监听;测试连通性 :在 HAProxy 节点(20)执行
telnet172.25.254.100/24:9090、telnet172.25.254.200/24:9090,验证是否能连通;检查防火墙 :在 100/200 节点执行
firewall-cmd --list-ports,确认 9090 端口已放行;重启应用服务:在 100/200 节点重启 ZrLog/Tomcat,等待健康检查后,监控页服务器状态会变为绿色 UP。
补充:正常状态的参考
如果后端服务器正常,
zrlog_servers段会显示:
服务器
Status: UP(绿色),LastChk: L7OK in 2ms(7 层健康检查通过);
Backend 总状态: UP,业务可正常访问。
6.2 前端访问
-
主 VIP:
http://172.25.254.101 -
备 VIP:
http://172.25.254.102
6.3模拟故障
正常状态:
-
20 节点:持有 VIP1(101)(VI_1 Master),不持有 VIP2(102)(VI_2 Backup);
-
23 节点:持有 VIP2(102)(VI_2 Master),不持有 VIP1(101)(VI_1 Backup);
-
客户端访问 VIP1 → 100节点,访问 VIP2 → 200节点,两台服务器同时承载业务。
故障状态:
-
若 100节点宕机:200 节点的 VI_1 优先级(90)成为最高,自动接管 VIP1(100),此时 200 节点同时持有 VIP1 和 VIP2;
-
若 200 节点宕机:100 节点的 VI_2 优先级(90)成为最高,自动接管 VIP2(102),此时 20 节点同时持有两个 VIP;
-
故障恢复后,优先级高的节点会重新接管对应 VIP(默认抢占模式)。
ZrLog 高可用架构故障验证实操步骤(基于文档环境)
以下是针对
20节点(172.25.254.10)和23节点(172.25.254.20)双主故障场景的完整验证流程,包含环境检查、故障模拟、验证点、恢复操作全环节。前置准备
确认所有节点服务正常运行:
# 10/20节点检查HAProxy+Keepalived状态 systemctl status haproxy keepalived # 检查VIP归属(20节点应持有100,23节点应持有101) ip addr | grep -E "172.25.254.101|172.25.254.102" # 验证VIP可正常访问 curl -I http://172.25.254.101/ curl -I http://172.25.254.102/打开 HAProxy 监控页面(备用):浏览器访问
http://172.25.254.10:8080/haproxy-stats(账号admin/ 密码admin123),确认后端zrlog1/zrlog2 均为 UP 状态。
故障场景 1:10节点宕机(模拟整机故障)
步骤 1:模拟 10 节点宕机
直接在 10节点执行停机 / 断网操作(任选一种):
# 方式1:停止核心服务(模拟服务级故障) systemctl stop haproxy keepalived # 方式2:断开网卡(模拟网络/整机故障,更贴近真实场景) ifdown eth0 # 网卡名需与keepalived配置一致 ifup eth0 # 重新启用ens160网卡步骤 2:验证 20 节点接管 VIP1
在 20节点检查 VIP 归属:
ip addr | grep -E "172.25.254.101|172.25.254.102"✅ 预期结果:20节点同时显示
1172.25.254.101和172.25.254.102(两个 VIP 均漂移到 20节点)。
验证 VIP 访问可用性:
# 多次访问两个VIP,确认无中断 for i in {1..5}; do curl http://172.25.254.101/; sleep 1; done for i in {1..5}; do curl http://172.25.254.102/; sleep 1; done✅ 预期结果:所有请求返回
200 OK,无 502 / 超时错误。查看 20 节点 Keepalived 日志(确认切换过程):
journalctl -u keepalived -f | grep "VI_1" [root@LB-node5 ~]# journalctl -u keepalived -f | grep "VI_1" 3月 25 19:03:56 LB-node5 Keepalived_vrrp[31878]: (VI_1) Sending/queueing gratuitous ARPs on eth0 for 172.25.254.101✅ 预期日志:
VRRP_Instance(VI_1) Entering MASTER STATE(VI_1 从 Backup 切换为 Master)。步骤 3:恢复 10节点
# 方式1:恢复网卡(若用断网模拟) ifup eth0 # 方式2:重启服务 systemctl start keepalived haproxy # 验证VIP漂移回20节点 sleep 10 # 等待VRRP协商(默认1秒心跳,约10秒完成抢占) ip addr | grep 172.25.254.101 # 10节点应重新持有100 ip addr | grep 172.25.254.102 # 20节点仍持有101
故障场景 2:20节点宕机(模拟整机故障)
步骤 1:恢复初始状态
确保 10节点已恢复正常(持有 100)、20 节点持有 101,验证基础访问正常。
步骤 2:模拟 20 节点宕机
在 20 节点执行停机 / 断网操作:
# 方式1:停止核心服务 systemctl stop haproxy keepalived # 方式2:断开网卡 ifdown eth0步骤 3:验证 10 节点接管 VIP2
在 10 节点检查 VIP 归属:
ip addr | grep -E "172.25.254.101|172.25.254.102"✅ 预期结果:10节点同时显示172.25.254.101和172.25.254.102(两个 VIP 均漂移到 10 节点)。
验证 VIP 访问可用性:
for i in {1..3}; do curl -I -s http://172.25.254.101/ | grep "HTTP/1.1"; sleep 1; done for i in {1..3}; do curl -I -s http://172.25.254.102/ | grep "HTTP/1.1"; sleep 1; done


