ZrLog 高可用反向代理架构

基于 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 服务本身的运行状态:

  1. 进程基本信息

    • pid = 12284:HAProxy 进程 ID 正常,进程数 nbproc = 1(单进程模式,符合配置),线程数 nbthread = 2

    • uptime = 0d 0h02m11s:HAProxy 已启动 2 分 11 秒,服务正常运行;

    • Running tasks: 0/15; idle = 100 %:当前无运行中任务,空闲率 100%,说明无业务请求压力。

  2. 系统资源限制

    • maxconn = 4000:全局最大并发连接数(和你配置的 globalmaxconn 4000 一致);

    • current conns = 1:当前仅 1 个连接(就是你访问监控页的连接),无业务连接;

    • conn rate = 1/sec:连接速率 1 次 / 秒,bit rate = 0.000 kbps:当前无业务流量。

  3. 状态色标说明

    • 绿色 = active UP(正常在线),红色 = active or backup DOWN(故障离线),黄色 = 过渡状态;

    • 图中后端 zrlog1/zrlog2 为红色,说明两台后端 ZrLog 服务器全部处于 DOWN 状态


二、stats 监听段(监控页自身的前端)

这是你访问的 8080/haproxy-stats 监控端口的状态:

  1. Frontend(前端)

    • Status: OPEN:监控端口正常监听,可正常访问;

    • Sessions: Cur=1:当前 1 个连接(你的浏览器访问),Total=3:累计 3 次连接;

    • Bytes In=461 / Out=263:监控页的请求 / 响应字节数,无业务流量。

  2. Backend(后端)

    • Status: 2m11s UP:后端状态正常,和 HAProxy 启动时间一致;

    • LastChk: 2m11s UP:最后一次健康检查正常,监控服务自身无故障。


三、http-in 前端段(业务 80 端口监听)

这是你配置的 frontend http-in(监听 80 端口,业务入口)的状态:

  1. 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 DOWN L4CON in 0ms 第 4 层连接失败(HAProxy 连不上 9090 端口,服务器 / 服务宕机)
zrlog2(172.25.254.20:9090) 2m10s DOWN L4CON 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,业务完全不可用


五、从页面能直接得出的结论(核心)

  1. HAProxy 服务本身正常:进程运行、80/8080 端口正常监听,监控页可正常访问;

  2. 两台 ZrLog 应用服务器(172.25.254.100/24:9090)全部故障离线:HAProxy 无法连接到后端 9090 端口,业务完全不可用;

  3. 故障原因定位:

    复制代码
    L4CON in 0ms

    是 TCP 层连接失败,说明:

    • 要么 100/200服务器的 9090 端口未监听(ZrLog/Tomcat 服务未启动 / 端口错);

    • 要么服务器防火墙 / 网络拦截了 9090 端口,HAProxy 无法连通;

    • 要么服务器本身宕机 / 网络不通。

  4. 当前无业务流量:所有连接数、流量指标均为 0,仅监控页自身有连接。


六、下一步排查步骤(对应页面问题)

  1. 检查后端服务器服务状态 :在 21/24 节点执行 ss -tnlp | grep 9090,确认 9090 端口是否被 ZrLog/Tomcat 监听;

  2. 测试连通性 :在 HAProxy 节点(20)执行 telnet 172.25.254.100/24: 9090telnet 172.25.254.200/24: 9090,验证是否能连通;

  3. 检查防火墙 :在 100/200 节点执行 firewall-cmd --list-ports,确认 9090 端口已放行;

  4. 重启应用服务:在 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 双主故障场景的完整验证流程,包含环境检查、故障模拟、验证点、恢复操作全环节。

前置准备

  1. 确认所有节点服务正常运行:

    复制代码
    # 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/
  2. 打开 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

  1. 在 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节点)。

  1. 验证 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 / 超时错误。

  2. 查看 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
  3. ✅ 预期日志: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

  1. 在 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 节点)。

  1. 验证 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

相关推荐
xyzhan2 小时前
使用Delphi开发混凝土生产车间自动化过程控制系统的仿真系统
运维·物联网·自动化·delphi·仿真·混凝土车间
AAA阿giao2 小时前
从零到精通 NestJS:深度剖析待办事项(Todos)项目,全面解析 Nest 架构、模块与数据流
架构·typescript·node.js·nestjs·全栈开发·后端框架
默|笙2 小时前
【Linux】进程间通信(5)_消息队列与信号量
linux
半路_出家ren2 小时前
Nginx基础学习
运维·网络·网络协议·学习·nginx·网络安全
浅念-2 小时前
Linux 基础命令与核心知识点
linux·数据结构·c++·经验分享·笔记·算法·ubuntu
CaracalTiger2 小时前
Windows 环境下 OpenClaw 的安装与千问Qwen、Kimi、MiniMax、GLM国产大模型配置完全指南
运维·ide·windows·开源·github·aigc·ai编程
默|笙2 小时前
【Linux】进程信号(2)_信号保存
linux·运维·服务器
youyoulg2 小时前
opencode在Linux终端中无法复制文字的解决方法
linux·服务器·人工智能
2301_807367192 小时前
Linux(CentOS)安装 Nginx
linux·nginx·centos