【双机高可用部署方案-前后端部署】

1. 引言

在工业物联网场景中,起重机安全监控系统的稳定运行直接关系到生产安全。本文将基于一套真实的双机高可用部署方案,详细讲解后端服务(Spring Boot)与前端应用(Vue + Nginx)在 Linux 服务器上的部署、配置与维护全流程。无论你是运维工程师还是全栈开发者,都能从中获得可直接落地的实践经验。


2. 系统架构与高可用设计

本平台部署于 两台物理工控机(Node A 与 Node B) 上,采用高可用架构设计,确保监控系统和数据采集的不间断运行。

2.1 核心设计方案

  1. 双节点冗余部署:Node A 和 Node B 分别部署完整的前端(Nginx 静态托管)和后端(Spring Boot 服务)程序。
  2. 底层数据库实时同步(达梦双写)
    • 底层达梦数据库(DM8)配置了 Data Watch 双机热备 物理归档同步方案。
    • 数据在主库(Primary)与备库(Standby)之间进行实时双写与增量对齐,确保数据一致性。
  3. 本地化数据库访问
    • 为了保证高性能与服务高内聚,每一个节点的 Spring Boot 服务仅连接自己本机的数据库服务 (连接配置为 127.0.0.1:5236)。
    • Node A 的后端仅读写 Node A 的数据库,Node B 的后端仅读写 Node B 的数据库。
  4. 网络层 Keepalived 高可用
    • 在两台工控机上配置 Keepalived,设置统一的 虚拟 IP(VIP: 192.160.6.9
    • 所有外部访问流量(用户浏览器、PLC 数据写入等)全部通过 VIP 进行接入。
    • 虚拟 IP 会漂移并绑定到当前的"主节点"。当主节点发生硬件故障、网络故障或 Spring Boot 服务挂掉时,虚拟 IP 会自动漂移到备用节点,实现秒级无感知切换。

2.2 软硬件配置要求

  • 硬件设备:2 台物理工控机(Node A 与 Node B)
  • 操作系统:银河麒麟操作系统(Kylin OS,基于 Linux 内核)
  • 数据库系统:达梦数据库 DM8(配置 Data Watch 主备同步)
  • 主要运行软件
    • JDK 1.8(后端服务运行环境)
    • Nginx(前端静态托管及反向代理服务)
    • Keepalived(虚拟 IP 漂移及高可用路由)

2.3 系统架构拓扑图

#mermaid-svg-yMK0xgZwBAdoyJzF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yMK0xgZwBAdoyJzF .error-icon{fill:#552222;}#mermaid-svg-yMK0xgZwBAdoyJzF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yMK0xgZwBAdoyJzF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yMK0xgZwBAdoyJzF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yMK0xgZwBAdoyJzF .marker.cross{stroke:#333333;}#mermaid-svg-yMK0xgZwBAdoyJzF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yMK0xgZwBAdoyJzF p{margin:0;}#mermaid-svg-yMK0xgZwBAdoyJzF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster-label text{fill:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster-label span{color:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster-label span p{background-color:transparent;}#mermaid-svg-yMK0xgZwBAdoyJzF .label text,#mermaid-svg-yMK0xgZwBAdoyJzF span{fill:#333;color:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF .node rect,#mermaid-svg-yMK0xgZwBAdoyJzF .node circle,#mermaid-svg-yMK0xgZwBAdoyJzF .node ellipse,#mermaid-svg-yMK0xgZwBAdoyJzF .node polygon,#mermaid-svg-yMK0xgZwBAdoyJzF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yMK0xgZwBAdoyJzF .rough-node .label text,#mermaid-svg-yMK0xgZwBAdoyJzF .node .label text,#mermaid-svg-yMK0xgZwBAdoyJzF .image-shape .label,#mermaid-svg-yMK0xgZwBAdoyJzF .icon-shape .label{text-anchor:middle;}#mermaid-svg-yMK0xgZwBAdoyJzF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yMK0xgZwBAdoyJzF .rough-node .label,#mermaid-svg-yMK0xgZwBAdoyJzF .node .label,#mermaid-svg-yMK0xgZwBAdoyJzF .image-shape .label,#mermaid-svg-yMK0xgZwBAdoyJzF .icon-shape .label{text-align:center;}#mermaid-svg-yMK0xgZwBAdoyJzF .node.clickable{cursor:pointer;}#mermaid-svg-yMK0xgZwBAdoyJzF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yMK0xgZwBAdoyJzF .arrowheadPath{fill:#333333;}#mermaid-svg-yMK0xgZwBAdoyJzF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yMK0xgZwBAdoyJzF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yMK0xgZwBAdoyJzF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yMK0xgZwBAdoyJzF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yMK0xgZwBAdoyJzF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yMK0xgZwBAdoyJzF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster text{fill:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF .cluster span{color:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yMK0xgZwBAdoyJzF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yMK0xgZwBAdoyJzF rect.text{fill:none;stroke-width:0;}#mermaid-svg-yMK0xgZwBAdoyJzF .icon-shape,#mermaid-svg-yMK0xgZwBAdoyJzF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yMK0xgZwBAdoyJzF .icon-shape p,#mermaid-svg-yMK0xgZwBAdoyJzF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yMK0xgZwBAdoyJzF .icon-shape .label rect,#mermaid-svg-yMK0xgZwBAdoyJzF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yMK0xgZwBAdoyJzF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yMK0xgZwBAdoyJzF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yMK0xgZwBAdoyJzF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 工控机 Node B - 192.160.6.6 (当前备节点)
工控机 Node A - 192.160.6.7 (当前主节点)
统一访问虚拟 IP: 192.160.6.9
反向代理 /crane-monitor
连接本机库 127.0.0.1
反向代理 /crane-monitor
连接本机库 127.0.0.1
达梦 Data Watch 实时双写同步
转发流量 (主路由)
故障时漂移绑定 (备路由)
客户端 / 用户浏览器 / PLC设备
Keepalived 虚拟 IP
Nginx 业务端口 8888
Spring Boot 端口 82
本地达梦数据库 5236 - 主库
Nginx 业务端口 8888
Spring Boot 端口 82
本地达梦数据库 5236 - 备库


3. 后端部署手册 (monitor-server)

3.1 部署环境要求

  • 操作系统:银河麒麟操作系统 (Kylin OS)
  • JDK 版本 :JDK 8 (OpenJDK 或 Oracle JDK,安装路径如:/home/server/soft/java)
  • 数据库:达梦数据库 DM8(配置为本地高可用)
  • 高可用 VIP :Keepalived 虚拟 IP (192.160.6.9)

3.2 目录规划

在部署服务器上创建后端服务目录:

  • 服务器路径/home/server/soft/crane/backend

目录结构

text 复制代码
/home/server/soft/crane/backend/
├── monitor-server-1.0-SNAPSHOT.jar   # 后端 jar 包
└── logs/                             # 日志存放目录(需手动创建或由服务自动生成)
    ├── stdout.log                    # 系统运行日志 / 标准输出日志
    ├── gc.log                        # JVM 垃圾回收日志
    └── heapdump.hprof                # OOM 堆内存快照文件(仅在发生内存溢出时生成)

3.3 编译、打包与文件分发

  1. 本地编译打包

    在开发环境或集成构建环境的项目根目录下,执行 Maven 打包命令:

    bash 复制代码
    mvn clean package -Dmaven.test.skip=true

    打包完成后,将在项目子模块 monitor-server/target/ 目录下生成可运行的二进制 Jar 包:monitor-server-1.0-SNAPSHOT.jar

  2. 创建服务器部署路径

    在服务器上,使用 mkdir 命令创建后端项目目录和日志目录:

    bash 复制代码
    mkdir -p /home/server/soft/crane/backend/logs
  3. 分发并上传包文件

    通过 SFTP/SCP 等工具,将打包好的 monitor-server-1.0-SNAPSHOT.jar 上传到服务器的部署路径 /home/server/soft/crane/backend/ 下。


3.4 Systemd 守护进程配置

在包文件上传完成后,需要在服务器上配置 Systemd 守护进程服务,以确保程序在后台自动运行并具备异常自愈和开机自启的能力。

3.4.1 创建并配置服务文件

在服务器 /etc/systemd/system 目录下创建服务配置文件 monitor.service

bash 复制代码
sudo vi /etc/systemd/system/monitor.service

写入以下配置内容:

ini 复制代码
[Unit]
Description=Crane Monitor Backend Service
After=syslog.target network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/server/soft/crane/backend
# 注意:请确认 /home/server/soft/java/bin/java 为您服务器上实际的 java 命令绝对路径
ExecStart=/home/server/soft/java/bin/java -server -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+ParallelRefProcEnabled -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/server/soft/crane/backend/logs/heapdump.hprof -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/server/soft/crane/backend/logs/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -Dfile.encoding=UTF-8 -Djava.awt.headless=true -jar monitor-server-1.0-SNAPSHOT.jar

SuccessExitStatus=143
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
3.4.2 启动守护进程服务

配置完成后,依次执行以下命令加载、启动服务并设置开机自动启动:

bash 复制代码
# 重新加载 Systemd 配置以识别新创建的 monitor.service
systemctl daemon-reload

# 启动后端服务
systemctl start monitor.service

# 设置服务为开机自启动
systemctl enable monitor.service
3.4.3 服务管理常用命令

在后续维护中,您可以通过以下命令来管理后端服务的运行状态:

  • 停止服务

    bash 复制代码
    systemctl stop monitor.service
  • 重启服务

    bash 复制代码
    systemctl restart monitor.service
  • 查看服务运行状态

    bash 复制代码
    systemctl status monitor.service
  • 禁用开机自启

    bash 复制代码
    systemctl disable monitor.service
  • 查看实时应用日志 (journalctl)

    bash 复制代码
    journalctl -u monitor.service -f
3.4.4 服务部署验证

服务启动后,进行以下步骤验证部署是否成功:

  • 运行状态检查 :执行 systemctl status monitor.service 观察输出中的 Active: active (running) 状态。

  • 服务端口监听检查 :执行以下命令,确认后端服务的 82 端口是否处于监听状态:

    bash 复制代码
    netstat -ntlp | grep 82
  • 应用健康度联调检查:通过 HTTP 访问 Spring Boot 提供的 Actuator 端点:

    bash 复制代码
    curl http://127.0.0.1:82/crane-monitor/actuator/health

    (如果返回 {"status":"UP",...},则表示后端应用已经成功运行,且本地达梦数据库(DM8)连接完全正常。)


4. 前端部署手册 (monitor-ui)

4.1 部署环境要求

  • 构建环境:Node.js (推荐 v14.x 或 v16.x) + npm/yarn
  • 运行环境:Nginx (建议 1.18.0+)
  • 前端静态文件部署路径/home/server/soft/crane/frontend/dist

4.2 前端打包

  1. 安装依赖

    在本地或构建机的 monitor-ui 目录下执行依赖安装:

    bash 复制代码
    npm install
    # 或使用 yarn
    yarn install
  2. 生产构建

    执行前端打包编译命令:

    bash 复制代码
    npm run build
    # 或使用 yarn
    yarn build

    编译完成后会在 monitor-ui/ 下生成 dist/ 目录。

  3. 上传至服务器

    dist/ 目录打包(如 dist.tardist.zip)并上传至服务器,解压到 /home/server/soft/crane/frontend/dist。确保在该目录下可以直接看到 index.htmlassets/ 文件夹。

4.3 Nginx 配置

4.3.1 Nginx 全局配置说明

如果服务器尚未配置 Nginx,可以使用以下配置作为 Nginx 主配置文件 nginx.conf 的标准配置。主配置文件的常见路径为:/home/server/soft/nginx/conf/nginx.conf/etc/nginx/nginx.conf

nginx 复制代码
user server;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /home/server/soft/nginx/conf/conf.d/*.conf;

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2 default_server;
#        listen       [::]:443 ssl http2 default_server;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers HIGH:!aNULL:!MD5;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        include /etc/nginx/default.d/*.conf;
#
#        location / {
#        }
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}
4.3.2 项目专用配置 (crane-monitor.conf)

/home/server/soft/nginx/conf/conf.d/ 目录下创建项目的 Nginx 配置文件 crane-monitor.conf。内容如下:

nginx 复制代码
server {
    # 监听起重机监控平台指定的业务端口
    listen       8888; 
    server_name  _; 

    # 1. 静态资源托管配置
    location / {
        root /home/server/soft/crane/frontend/dist; 
        try_files $uri $uri/ @router;
        index index.html; 
    }    

    # 支持 Vue Router HTML5 History 模式的路由重定向
    location @router {
        rewrite ^.*$ /index.html last;
    }

    # 2. 后端接口反向代理配置
    location /crane-monitor {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # 代理到本地运行的 Spring Boot 后端服务端口 (82)
        proxy_pass http://127.0.0.1:82/crane-monitor; 
        
        # 支持 WebSocket 连接(起重机实时数据推送)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Origin "";
    }
}
4.3.3 Nginx Systemd 守护进程配置

为了将 Nginx 配置为系统守护进程并实现开机自启,请在 /etc/systemd/system/ 目录下创建 nginx.service 文件:

bash 复制代码
sudo vi /etc/systemd/system/nginx.service

写入以下配置内容:

ini 复制代码
[Unit]
Description=The NGINX HTTP and reverse proxy server (Custom)
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
# 对应您 nginx.conf 中配置的 pid 路径
PIDFile=/run/nginx.pid
# 启动前进行配置文件语法检查
ExecStartPre=/home/server/soft/nginx/sbin/nginx -t -c /home/server/soft/nginx/conf/nginx.conf
# 启动命令
ExecStart=/home/server/soft/nginx/sbin/nginx -c /home/server/soft/nginx/conf/nginx.conf
# 重载配置命令
ExecReload=/home/server/soft/nginx/sbin/nginx -s reload -c /home/server/soft/nginx/conf/nginx.conf
# 停止命令
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
4.3.4 Nginx 服务管理与重启生效

配置好 nginx.service 后,可以使用以下 Systemd 命令管理 Nginx 服务:

  • 重新加载 Systemd 配置

    bash 复制代码
    systemctl daemon-reload
  • 启动 Nginx 服务

    bash 复制代码
    systemctl start nginx.service
  • 停止 Nginx 服务

    bash 复制代码
    systemctl stop nginx.service
  • 重启 Nginx 服务

    bash 复制代码
    systemctl restart nginx.service
  • 重新加载 Nginx 配置 (平滑重载,不中断连接)

    bash 复制代码
    systemctl reload nginx.service
  • 设置 Nginx 开机自启

    bash 复制代码
    systemctl enable nginx.service
  • 查看 Nginx 服务状态

    bash 复制代码
    systemctl status nginx.service

(注:如果尚未配置 nginx.service 守护进程,也可以通过原生命令进行配置文件检查与平滑重启:)

bash 复制代码
# 验证 nginx 配置文件语法是否正确
/home/server/soft/nginx/sbin/nginx -t -c /home/server/soft/nginx/conf/nginx.conf

# 重新加载 Nginx 配置
/home/server/soft/nginx/sbin/nginx -s reload -c /home/server/soft/nginx/conf/nginx.conf

5. 部署验证与联调测试

5.1 联调步骤

  1. 打开浏览器,输入访问地址(若 Keepalived 已配置,则访问虚拟 IP
相关推荐
企业数字化笔记1 小时前
固定资产还有借用记录能报废吗?Java前置检查、停止折旧与SQL验收
java·开发语言·sql
飞虹地星海1 小时前
从零到一跑通苍穹外卖:一个大二学生的暑假项目复盘
java
她的男孩1 小时前
账号锁定配了"错 4 次锁 30 分钟",我连错 100 次一次没锁上:扒完 4091 行认证源码,找到 5 个坑
java·后端·架构
程序猿乐锅1 小时前
【黑马点评 | 第二篇】Redis 缓存更新策略与商铺缓存实现
java·网络·redis·spring·mybatis
livemetee1 小时前
MySQL联合唯一索引(code,deleted)与逻辑删除问题
java·数据库
MacroZheng1 小时前
Redis官方发布高颜值可视化工具,功能更是强的离谱!
java·redis·后端
wuminyu1 小时前
纯轻量级锁体系下C2编译器锁粗化和消除机制剖析
java·linux·c语言·jvm·c++
运维全栈笔记1 小时前
Nginx 模块化多业务站点通用配置模板
linux·运维·nginx
ss2731 小时前
AI全栈实战 | 1.4-02 Spring AOP:@Transactional 失效的 N 种场景,根因其实只有一个
java·spring·ai编程