ZrLog 高可用部署

一、架构说明

角色 IP 部署内容
数据库服务器 172.25.254.20 MariaDB
应用服务器 1 172.25.254.21 ZrLog(Maven 构建) + Tomcat + 阿里云镜像优化
应用服务器 2 172.25.254.22 ZrLog(Maven 构建) + Tomcat + 阿里云镜像优化
Nginx Master 1 172.25.254.23 Nginx + Keepalived + 邮件通知 + 阿里云镜像优化
Nginx Master 2 172.25.254.24 Nginx + Keepalived + 邮件通知 + 阿里云镜像优化
VIP 1 172.25.254.100 Keepalived 虚拟 IP
VIP 2 172.25.254.200 Keepalived 虚拟 IP

二、基础环境配置(所有主机)

2.1 挂载本地软件仓库

复制代码
[root@node1 ~]# mount /dev/sr0   /mnt
mount: /mnt: WARNING: source write-protected, mounted read-only.

2.2 安装基础依赖(所有主机)

复制代码
[root@node1 ~]# dnf install -y wget vim   tree net-tools   zip

三、部署 MariaDB(172.25.254.20)

复制代码
#安装MariaDB(阿里云源)
[root@node1 ~]# dnf install -y mariadb-server

#启动并设置开机自启
[root@node1 ~]# systemctl start mariadb && systemctl enable mariadb

#初始化数据库并配置ZrLog权限
[root@node1 ~]# 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;
"
# 开放数据库端口
[root@node1 ~]# firewall-cmd --add-port=3306/tcp --permanent
[root@node1 ~]# firewall-cmd --reload

四、部署 ZrLog 应用服务器(172.25.254.21 和 172.25.254.22)

4.1 安装 JDK 11

复制代码
# 1.上传jdk-11.tar.gz到/root目录,执行解压
[root@node2 ~]# tar -zxf jdk-11_linux-x64_bin.tar.gz  
[root@node2 ~]# mv  jdk-11  jdk11

# 2.配置全局环境变量(永久生效)
[root@node2 ~]# 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.生效并验证
[root@node2 ~]# source /etc/profile.d/jdk.sh
[root@node2 ~]# java -version  # 输出JDK版本即成功

4.2 Maven(配置阿里云镜像)

复制代码
# 1. 下载 Maven 3.9.6(适配JDK 11),解压并重命名
[root@node2 ~]# tar -zxf   apache-maven-3.9.14-bin.tar.gz 
[root@node2 ~]# mv apache-maven-3.9.14 maven

# 2. 配置全局环境变量
[root@node2 ~]# cat > /etc/profile.d/maven.sh << 'EOF'
export MAVEN_HOME=/root/maven
export PATH=$MAVEN_HOME/bin:$PATH
EOF

[root@node2 ~]# source /etc/profile.d/maven.sh
[root@node2 ~]# mvn -version  # 输出Maven版本即成功

[root@node2 ~]# vim /root/maven/conf/settings.xml
160     <mirror>
161       <id>maven-default-http-blocker</id>
162       <mirrorOf>external:http:*</mirrorOf>
163       <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
164       <url>http://0.0.0.0/</url>
165       <blocked>true</blocked>
166     </mirror>
167 
168     <mirror>
169     <id>tencentmaven</id>
170     <mirrorOf>central</mirrorOf>
171     <url>https://maven.aliyun.com/repository/public/</url>
172 </mirror>
173   </mirrors>

4.3 下载 ZrLog 源码并通过 Maven 构建

复制代码
# 1.解压到指定目录,避免文件混乱
[root@node2 ~]# unzip -q zrlog-3.3.0-1811fd7-release.zip -d zrlog-src
[root@node2 ~]# cd zrlog-src

# 2.进入pom.xml所在目录
[root@node2 ~]# find   /root/zrlog-src/   -name  pom.xml   
/root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml

# 3.配置阿里云镜像(解决依赖下载慢/失败)
[root@node2 ~]# mv /root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml /root/zrlog-src/META-INF/maven/com.hibegin/package/pom.xml.bak

# 4.写入全新的独立pom.xml(无需父POM,直接构建War包)
[root@node2 ~]# 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@node2 ~]# cd  /root/zrlog-src/META-INF/maven/com.hibegin/package/

# 5.执行Maven打包(-DskipTests跳过测试,加快构建速度)
[root@node2 package]# mvn clean package -DskipTests

4.4 复制 War 包并清理旧数据

复制代码
[root@node2 ~]# tar -xaf   apache-tomcat-10.1.52.tar.gz 
[root@node2 ~]# mv apache-tomcat-10.1.52   tomcat10

#复制War包到Tomcat webapps目录,重命名为ROOT.war(直接访问根路径)
[root@node2 ~]# cd  /root/zrlog-src/META-INF/maven/com.hibegin/package/
[root@node2 package]# cp target/zrlog.war   /root/tomcat10/webapps/ROOT.war


#清理Tomcat旧解压文件(避免冲突)
[root@node2 package]# rm -rf /root/tomcat10/webapps/ROOT

4.5 启动 Tomcat 并验证

复制代码
#启动Tomcat
[root@node2 ~]# /root/tomcat10/bin/startup.sh

#查看启动日志(确认War包解压、服务无报错)
[root@node2 ~]# tail -f /root/tomcat10/logs/catalina.out

启动成功标识:


五、部署 Nginx + Keepalived(172.25.254.23 和 172.25.254.24)

5.1 安装 Nginx 和 Keepalived(阿里云源)

复制代码
[root@node4 ~]# dnf install -y nginx keepalived

5.2 配置 Nginx 负载均衡

复制代码
[root@node4 ~]# cat > /etc/nginx/conf.d/zrlog.conf << 'EOF'
upstream zrlog_backend {
    server 172.25.254.21:8080;
    server 172.25.254.22:8080;
}

server {
    listen 80;
    server_name _;

    location / {
        proxy_pass http://zrlog_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 反向代理优化
        proxy_connect_timeout 5;
        proxy_send_timeout 10;
        proxy_read_timeout 10;
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 4 32k;
    }
}
EOF

#启动Nginx并设置开机自启
[root@node4 ~]# systemctl start nginx  &&  systemctl enable nginx
[root@node4 ~]# nginx -t

5.3 编写Nginx健康检查脚本

复制代码
[root@node4 ~]# cat > /usr/local/bin/nginx_check.sh << 'EOF'
#!/bin/bash
# Nginx健康检查脚本:检测进程+端口,双重验证
NGINX_PID=$(ps -ef | grep nginx | grep -v grep | grep -v "nginx_check.sh" | wc -l)
NGINX_PORT=$(netstat -tnlp | grep :80 | grep nginx | wc -l)

# 若进程数为0或80端口未监听,判定Nginx故障,返回非0(触发Keepalived故障)
if [ $NGINX_PID -eq 0 ] || [ $NGINX_PORT -eq 0 ]; then
    # 尝试重启Nginx(可选,失败则彻底触发故障)
    systemctl restart nginx
    sleep 3
    # 再次检测,仍失败则返回1
    NGINX_PID=$(ps -ef | grep nginx | grep -v grep | wc -l)
    NGINX_PORT=$(netstat -tnlp | grep :80 | grep nginx | wc -l)
    if [ $NGINX_PID -eq 0 ] || [ $NGINX_PORT -eq 0 ]; then
        exit 1
    fi
fi
# 检测成功,返回0
exit 0
EOF

# 赋予执行权限(关键,否则Keepalived无法调用)
[root@node4 ~]# chmod +x /usr/local/bin/nginx_check.sh

# 测试脚本:正常运行Nginx时返回0,停止Nginx时返回1
[root@node4 ~]# /usr/local/bin/nginx_check.sh
[root@node4 ~]# echo $?  # 输出0=正常,1=故障

5.4 创建 Shell 邮件发送脚本

复制代码
#安装邮件,并提供可执行权限
[root@node4 ~]# yum install s-nail   -y 
[root@node4 ~]# chmod  755 /etc/s-nail.rc

#编辑 mailx 主配置文件
[root@node4 ~]# vim /etc/s-nail.rc
#在文件末尾添加以下内容(替换为你的网易邮箱信息)
set from="xxxxxxxxx@163.com"  # 发件人邮箱
set smtp="smtps://smtp.163.com:465"  #网易邮箱 SMTP 地址+端口
set smtp-auth-user="xxxxxxxxxxx@163.com"  # 邮箱账号
set smtp-auth-password="你的网易邮箱授权码"  # 替换为新生成的授权码(关键!)
set smtp-auth=login  # 认证方式
set ssl-verify=ignore  # 忽略 SSL 验证(避免版本问题)
set nss-config-dir=/etc/pki/nssdb/  # SSL 证书路径(系统默认)

#执行以下命令,测试基础发送
[root@node4 ~]# echo "这是 Keepalived 邮件通知测试内容" | mailx -s "测试邮件" xxxxxxxxxxx@163.com

5.5 创建 Keepalived 通知脚本

复制代码
[root@node4 ~]# cat > /usr/local/bin/keepalived_mail.sh << 'EOF'
#!/bin/bash
# 参数:$1 = 状态(master/backup/fault)

# 配置参数
VIP="172.25.254.100"  # 你的 VIP 地址
TO_EMAIL="xxxxxxxxx@163.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

5.6 配置 Keepalived(双主模式)

  • 172.25.254.100(VI_1):当前服务器作为 MASTER(主节点) 持有这个 VIP;
  • 172.25.254.200(VI_2):当前服务器作为 BACKUP(备节点),仅当持有该 VIP 的主节点故障时才接管;
  • 配合 notify 脚本,在节点角色切换(主 / 备 / 故障)时执行自定义操作(比如切换 Nginx 配置、发送告警)。

172.25.254.23配置:

复制代码
[root@node4 ~]# cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
   router_id LVS_20
}

vrrp_script check_nginx {
    script "/usr/local/bin/nginx_check.sh"  # 调用健康检查脚本
    interval 2  
    weight -20  
    fall 3
    rise 2   
}

vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.25.254.100
    }
    track_script {
        check_nginx
    }
    # 状态切换通知脚本:节点角色变化时执行指定脚本,并传递参数(master/backup/fault)
    # notify_master:节点成为主节点时执行
    # notify_backup:节点成为备节点时执行
    # notify_fault:节点故障时执行
    notify_master "/usr/local/bin/keepalived_mail.sh master"
    notify_backup "/usr/local/bin/keepalived_mail.sh backup"
    notify_fault "/usr/local/bin/keepalived_mail.sh fault"
}

vrrp_instance VI_2 {
    state BACKUP
    interface ens160
    virtual_router_id 52
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 2222
    }
    virtual_ipaddress {
        172.25.254.200
    }
    track_script {
        check_nginx
    }
    notify_master "/usr/local/bin/keepalived_mail.sh master"
    notify_backup "/usr/local/bin/keepalived_mail.sh backup"
    notify_fault "/usr/local/bin/keepalived_mail.sh fault"
}
EOF

172.25.254.24配置:

复制代码
[root@node5 ~]# cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
   router_id LVS_23
}

vrrp_script check_nginx {
    script "/usr/local/bin/nginx_check.sh"  # 调用健康检查脚本
    interval 2  
    weight -20  
    fall 3
    rise 2   
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.25.254.100
    }
    track_script {
        check_nginx
    }
    notify_master "/usr/local/bin/keepalived_mail.sh master"
    notify_backup "/usr/local/bin/keepalived_mail.sh backup"
    notify_fault "/usr/local/bin/keepalived_mail.sh fault"
}

vrrp_instance VI_2 {
    state MASTER
    interface ens160
    virtual_router_id 52
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 2222
    }
    virtual_ipaddress {
        172.25.254.200
    }
    track_script {
        check_nginx
    }
    notify_master "/usr/local/bin/keepalived_mail.sh master"
    notify_backup "/usr/local/bin/keepalived_mail.sh backup"
    notify_fault "/usr/local/bin/keepalived_mail.sh fault"
}
EOF

5.7 启动 Keepalived

复制代码
[root@node4 ~]# systemctl start keepalived
[root@node4 ~]# systemctl enable keepalived

六、验证结果

6.1 检查VIP是否生效(在负载均衡器上)

6.2 测试Maven构建产物访问

6.3 测试反向代理访问

6.4 VIP漂移

6.5 Nginx反向代理故障

相关推荐
重生的黑客9 小时前
Linux初识
linux·运维·服务器
李子焱9 小时前
第二节:n8n私有化部署全攻略(基于 Docker)
运维·docker·容器
evo-master9 小时前
linux环境准备和理解
linux·运维·服务器
Zhao136824553919 小时前
DP108B完全替代兼容进口的CM108B,USB 音频单芯片
linux·运维·音视频
云草桑9 小时前
Odoo 19.0 Docker Desktop快速部署 和Ubuntu24上安装1panel面板
运维·docker·容器·odoo
一个天蝎座 白勺 程序猿9 小时前
源网荷储实时互动需求下,时序数据库如何赋能新型电力系统?
数据库·时序数据库
吉普赛的歌9 小时前
【服务器】IIS, http自动跳转https
运维·服务器
艾莉丝努力练剑9 小时前
【Linux信号】Linux进程信号
linux·运维·服务器·学习·操作系统·进程·信号
笑梦无境9 小时前
mysql基础篇二(多年前整理)
数据库·mysql
齐齐大魔王9 小时前
linux-系统函数
linux·运维·microsoft