网信办前厅与食安迁移实施手册
2026-10-21前厅范围纠正:两套独立Store,业务数据库为zhct、zhct2。旧版前厅额外服务与数据库假设已撤销。前厅实施请优先使用修订后的独立28步手册。
旧服务器迁至新麒麟服务器 · MySQL 迁至达梦 · 现场顺序操作版
更新日期:2026-10-21(前厅范围纠正)。适用范围:前厅两套(Store所需PHP)、食安两套(Node.js 20),共四个业务库。达梦服务端已由厂家安装。本手册是实施方案,未在客户新服务器执行;正式发布包、客户最终备份和现场参数需在第 1—3 步锁定。
执行主线:先备份和演练 → 新机装运行环境及驱动 → 临时 MySQL 恢复并升级 → 四库迁入达梦 → 部署应用与文件 → 停写后迁最终数据 → 切入口 → 验收及回退交接。旧服务器不先做结构升级,保留原系统作为回退环境。
先看这张安排表
| 阶段 | 步骤 | 对旧业务的影响 |
|---|---|---|
| 准备 | 01—04 | 盘点、准备制品、演练备份;控制备份负载 |
| 新机环境 | 05—10 | 只配置新机,不启用正式业务任务 |
| 数据与应用演练 | 11—18 | 使用隔离副本和演练模式,不向真实设备发送业务指令 |
| 正式迁移 | 19—22 | 进入客户确认的停机窗口,旧机停写、新机接管 |
| 交接 | 23—24 | 监控、备份、恢复验证和回退决策 |
命令约定:Linux Bash;系统安装以 root 或有权限的管理员执行;PM2 命令统一用同一个食安运行用户。所有 CHANGE_ME 和“实际…”都要先填妥。命令按步骤执行,不要整页复制执行。给出的新目录和制品名是本手册约定,不代表这些包已经存在或已通过适配验收。
01|登记旧机现状与新机目标
执行位置:旧机、新机;本步只读。
先记录以下内容,现场表单见 实施登记表。密码另存客户认可的凭据文件,不写入登记表或本页面。
| 业务 | 源 MySQL 库 | 推荐达梦用户及同名模式 | 推荐业务表空间 |
|---|---|---|---|
| 前厅 1 · Store | zhct | ZHCT_APP | ZHCT_TBS |
| 前厅 2 · Store | zhct2 | ZHCT2_APP | ZHCT2_TBS |
| 食安 1 | foodsafe | FOODSAFE_APP | FOODSAFE_TBS |
| 食安 2 | foodsafe2 | FOODSAFE2_APP | FOODSAFE2_TBS |
推荐复用厂家已装的一个实例和一个端口,建立上述四组用户/模式/业务表空间。用户创建后自动产生同名默认模式,不重复建同名模式;表空间不是权限隔离边界,账号按实际业务最小授权。如果已有这些对象,先查归属,不覆盖重建。
旧机记录每套程序目录、Nginx 入口、PHP/Node 版本、配置文件、文件存储、Redis、MQTT、视频服务、设备地址、Cron、Supervisor、PM2、watchdog 和第三方回调。
cat /etc/os-release
uname -m
getconf LONG_BIT
ss -lntp
systemctl list-units --type=service --all | grep -Ei 'nginx|php|redis|mysql|dm|pm2|mosquitto|supervisor'
systemctl list-timers --all
crontab -l
# 若应用由 www 运行,也检查该用户;保留原内容
crontab -u www -l
pm2 list
supervisorctl status
没有安装对应组件时,该条记“不适用”,不据此安装全部组件。Nginx 的 -T、PM2 的环境输出可能含内部地址或口令,只在客户受控目录查看,不粘贴到公开材料。
通过标准:四库与四套应用一一对应;两套前厅均为独立Store,数据库分别为zhct和zhct2;所有后台写入入口和设备地址都有清单。第一套Store切换zhct,第二套Store切换zhct2,各自核对目标模式。
02|核验新麒麟、磁盘和厂家达梦
执行位置:新机;本步只读。
cat /etc/os-release
uname -m
ldd --version | head -1
command -v dnf yum apt-get
findmnt -T /data
findmnt -T /workspace
lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS
df -h /data /workspace
df -i /data /workspace
free -h
timedatectl
systemctl list-unit-files | grep -Ei 'DmService|DmAP'
不能只凭 ID=kylin 判断使用 apt 还是 yum;高级服务器版和桌面版可能不同,以实机软件源和包管理器为准。
厂家 2026-09-23 报告记载:麒麟 V10、海光平台、Pack30、端口 5236、32K 页、UTF-8、大小写不敏感、MySQL 兼容模式。现场核实是否仍一致。通过厂家管理工具,以管理账号交互登录后执行:
SELECT * FROM V$VERSION;
SELECT NAME FROM V$DATABASE;
SELECT INSTANCE_NAME, STATUS$ FROM V$INSTANCE;
SELECT PARA_NAME, PARA_VALUE
FROM V$DM_INI
WHERE PARA_NAME IN ('COMPATIBLE_MODE','MY_STRICT_TABLES',
'ORDER_BY_NULLS_FLAG','LENGTH_IN_CHAR','PORT_NUM');
字符集、页大小、大小写敏感等初始化属性结合管理工具和厂家记录核验,不因它们未出现在某个参数视图中就判异常。COMPATIBLE_MODE=4 只表示部分 MySQL 语法兼容,不等于应用已适配。
磁盘决定:正式应用、在线附件、缓存、当前日志放 /data;离线包、历史归档包放 /workspace。报告的 84.9 MB/s 与 1.1 MB/s 是相同 32KB oflag=dsync 写测试,不是所有读写速度;不要按该速度推算备份耗时。
厂家已配置实例位于 /data、备份及数据库归档位于 /workspace。保留数据库现有目录,不自行移动数据文件或归档文件。让厂家核查 /workspace 的实际备份吞吐、归档积压与上限;业务文件不得占用数据库核心目录。建议 /data 规划保留至少 20% 空闲空间。
通过标准:版本、架构、参数、监听、空间、时间正常;新机正式授权有效。报告当时记载的是截止 2026-12-25 的测试授权,必须核实后续是否已更换;历史记录不能替代现在的授权状态。
03|锁定发布包与四库升级包
执行位置:制包机;必须在停机前完成。
准备一个受控介质目录,例如 cac-migration-kit/,分为 runtime/、front/、foodsafe/、sql/、checks/、MANIFEST.sha256。包中不含真实密码、生产 dump、厂家授权文件。
| 制品 | 必须包含 |
|---|---|
| 前厅适配版 | 两套Store、完整vendor及本客户实际启用前端;各自版本与配置必须匹配 |
| 食安适配版 | 四个实际启用前端的 dist、后端完整 dist、运行依赖、package.json、锁文件、必要脚本/模板/共享库、Nginx 模板 |
| PHP 运行环境 | Store冻结PHP精确版本;扩展、ABI、运行配置和安装依赖 |
| 达梦客户端 | 与厂家实例和 PHP ABI 匹配的 Store PHP对应驱动及全部 DPI 依赖 |
| 食安运行环境 | Node.js 20 的固定补丁版、PM2 离线完整依赖、dmdb 的固定验收版 |
| 中间件 | 按旧机清单准备 Redis、Supervisor、Mosquitto及其依赖;不默认全部新增 |
| 数据升级 | 四库逐库预检、升级、后验 SQL;不需升级的库也需写明核验结果 |
| 迁移与核验 | 针对最终目标版本演练的 DTS 工程或转换程序、类型映射清单、行数和业务对账程序 |
前厅本机已存在达梦适配类;食安本机 standard 的 package.json 没有 dmdb,不能直接当成达梦发布版。以适配负责人交付的冻结提交、锁文件和验收结果为准。
# Linux 制包机:对包内文件生成清单,不把清单自身算进去
cd /受控制品目录/cac-migration-kit
find runtime front foodsafe sql checks -type f -print0 \
| sort -z | xargs -0 sha256sum > MANIFEST.sha256
# 新机收到介质后执行;必须在清单所在目录
sha256sum -c MANIFEST.sha256
macOS 单文件可用 shasum -a 256 文件名。离线包必须在匹配的麒麟版本、x86_64 架构和运行时环境制备/试装;不能直接复制 Mac 的整个 node_modules。前厅旧 PHP 的补丁版本按验收基线锁定,不在迁移窗口临时升级大版本。
通过标准:全部包存在、校验通过、在同环境演练;四库升级包和达梦适配包都有负责人。缺制品先补齐,不在停机后临时找驱动。
04|旧机做演练备份,验证能恢复
执行位置:旧机;在线备份需避开高峰。正式停写后会重做一次。
umask 077
install -d -m 700 /backup/cac-migration/rehearsal
在 root 或备份账号的私有目录创建两份连接配置,分别指向真实 MySQL 5.6 和 MySQL 8;用编辑器填写,不把密码放命令行。文件格式:
[client]
host=CHANGE_ME
port=3306
user=CHANGE_ME
password=CHANGE_ME
保存为 /root/cac-mysql56.cnf 与 /root/cac-mysql8.cnf 并 chmod 600。从配置文件确认主机、端口和账号后,使用匹配版本客户端:
MYSQL56_DUMP=/实际MySQL56客户端/bin/mysqldump
MYSQL8_DUMP=/实际MySQL8客户端/bin/mysqldump
BACKUP=/backup/cac-migration/rehearsal
# 一个前厅实例内四库一次导出,保留一致快照
if "$MYSQL56_DUMP" --defaults-extra-file=/root/cac-mysql56.cnf \
--single-transaction --quick --routines --events --triggers \
--hex-blob --default-character-set=utf8mb4 \
--databases zhct zhct2 \
> "$BACKUP/front.sql.part" 2> "$BACKUP/front.err"; then
mv "$BACKUP/front.sql.part" "$BACKUP/front.sql"
else
echo "前厅备份失败,保留part与err,不继续迁移"
exit 1
fi
if "$MYSQL8_DUMP" --defaults-extra-file=/root/cac-mysql8.cnf \
--single-transaction --quick --routines --events --triggers \
--hex-blob --default-character-set=utf8mb4 --set-gtid-purged=OFF \
--databases foodsafe foodsafe2 \
> "$BACKUP/foodsafe.sql.part" 2> "$BACKUP/foodsafe.err"; then
mv "$BACKUP/foodsafe.sql.part" "$BACKUP/foodsafe.sql"
else
echo "食安备份失败,保留part与err,不继续迁移"
exit 1
fi
sha256sum "$BACKUP/front.sql" "$BACKUP/foodsafe.sql" \
> "$BACKUP/dumps.sha256"
以上分支按退出码控制是否生成正式备份名;随后检查两个err文件中的警告,不使用部分文件。若库分布在多个 MySQL 实例,逐实例备份;跨实例一致性在正式阶段靠统一停写保证。--single-transaction 只保障事务表快照;MyISAM 等非事务表需停写或明确锁表方案,期间不能执行 DDL。
备份程序及配置:
# 把下面目录名替换成盘点出的真实目录;备份输出不能放进被打包目录
tar --acls --xattrs -czpf "$BACKUP/applications.tar.gz" \
-C /旧机应用父目录 前厅目录1 前厅目录2 食安目录1 食安目录2
crontab -l > "$BACKUP/root-crontab.txt"
crontab -u www -l > "$BACKUP/www-crontab.txt"
tar -tzf "$BACKUP/applications.tar.gz" >/dev/null
另备份实际 Nginx、PHP、Supervisor、PM2 ecosystem/dump、watchdog、证书、Redis/MQTT配置和所有外置上传目录。食安重点包括根目录与服务目录 .env*、data/、aiboxfile/、业务使用的其他存储路径。先确认是否采用 OSS/MinIO,数据库中的 URL 不代表文件一定在应用目录。
通过标准:备份可读,另有受控副本,SQL 已在隔离 MySQL 中恢复成功。备份文件存在不算恢复验证通过。
05|新机建立目录和运行用户
执行位置:新机管理员。
install -d -m 755 /data/apps/front1/store
install -d -m 755 /data/apps/front2/store
install -d -m 755 /data/apps/foodsafe1 /data/apps/foodsafe2
install -d -m 755 /data/app-logs /data/app-runtime
install -d -m 700 /data/migration /data/migration/evidence
install -d -m 700 /workspace/cac-packages
# 食安专用账户;已存在就复用并检查,不重复创建
id foodsafe || useradd -r -m -d /var/lib/foodsafe -s /bin/bash foodsafe
install -d -o foodsafe -g foodsafe -m 750 /data/app-logs/foodsafe1 /data/app-logs/foodsafe2
前厅使用运行环境已有的 www 用户,先 id www 核对。不要对 /data 全盘 chown,也不要把厂家 dmdba 文件改成应用用户。应用源码由发布账号管理,上传、日志、缓存目录按应用用户赋权;不要用 chmod -R 777。
备份包中的数字 UID/GID 不一定对应新机同名用户。恢复后用 stat、namei -l 和实际运行用户检查目录访问权限。启用 SELinux 时按当前策略设置目录标签,不能靠关闭保护绕过。
通过标准:程序、业务文件、日志、迁移材料分开;Nginx 可读前端文件,应用能写各自运行目录,两套文件不串用。
06|安装前厅Store运行环境
范围纠正:网信办前厅仅两套Store,数据库为zhct、zhct2。 本步骤旧版额外服务、数据库与双PHP要求已撤销。
详细操作以前厅独立手册第08步为准,包括操作位置、具体配置、成功标准和失败处理。PHP使用Store冻结版本,不因两套系统自动安装额外版本;两套站点、文件与任务分别核验。
07|安装Store所需达梦驱动
范围纠正:网信办前厅仅两套Store,数据库为zhct、zhct2。 本步骤旧版额外服务、数据库与双PHP要求已撤销。
详细操作以前厅独立手册第09步为准,包括操作位置、具体配置、成功标准和失败处理。PHP使用Store冻结版本,不因两套系统自动安装额外版本;两套站点、文件与任务分别核验。
08|设置Store中文编码与任务环境
范围纠正:网信办前厅仅两套Store,数据库为zhct、zhct2。 本步骤旧版额外服务、数据库与双PHP要求已撤销。
详细操作以前厅独立手册第10步为准,包括操作位置、具体配置、成功标准和失败处理。PHP使用Store冻结版本,不因两套系统自动安装额外版本;两套站点、文件与任务分别核验。
09|安装 Node.js 20、PM2 和食安达梦依赖
执行位置:制包机准备,新机安装。食安只部署生产 dist,不在新机运行开发构建。
有道笔记的 Node 20 方向适用,但不在离线新机执行在线 nvm 安装脚本。准备经官网校验、匹配麒麟 glibc 和架构的固定版本 Node 二进制包。以下以 x86_64 为例,实际版本填发布清单:
NODE_VERSION=CHANGE_ME
test "$NODE_VERSION" != CHANGE_ME || { echo '先填写Node精确版本'; exit 1; }
# NODE_VERSION形如v20.x.y;包必须已在同款麒麟试运行
cd /workspace/cac-packages/runtime
tar -tJf "node-${NODE_VERSION}-linux-x64.tar.xz" | head
install -d /opt/node
tar -xJf "node-${NODE_VERSION}-linux-x64.tar.xz" -C /opt/node
/opt/node/node-${NODE_VERSION}-linux-x64/bin/node -v
确认 /opt/node/current 尚不存在,或备份记录已有指向后,再建立指向新版本目录的链接:
ln -s "/opt/node/node-${NODE_VERSION}-linux-x64" /opt/node/current
本手册统一用 /opt/node/current/bin/node,systemd 和 PM2 不依赖交互 shell 的 nvm 环境。若报 GLIBC_x.xx not found,先换经过同版麒麟验证的 Node 构建;不升级/替换系统 glibc 来强行运行。
PM2 在同架构制包机以固定版本安装到单独前缀,连同依赖打包:
# 制包机:先设置发布清单中已验收的精确版本
: "${PM2_VERSION:?先设置PM2精确版本}"
npm install --prefix /受控制包目录/pm2 --omit=dev --save-exact "pm2@$PM2_VERSION"
tar -czf pm2-runtime.tar.gz -C /受控制包目录/pm2 node_modules package.json package-lock.json
# 新机:解压完整依赖到固定路径
install -d /opt/pm2
tar -xzf /workspace/cac-packages/runtime/pm2-runtime.tar.gz -C /opt/pm2
env PATH=/opt/node/current/bin:/usr/bin:/bin \
/opt/node/current/bin/node /opt/pm2/node_modules/pm2/bin/pm2 -v
食安 dmdb 必须存在于达梦发布包的运行依赖和锁文件中。制包时添加依赖的形态为 npm install --save-exact dmdb@已验收版本,不是现场临时装最新版;使用 pnpm 的发布分支应由 pnpm 同步锁文件,不能混用包管理器。
通过标准:Node 为冻结的 20.x 补丁版,PM2可以运行;发布包可在断网环境加载 dmdb、NestJS、tslib 等依赖,所有本地工作区包/链接目标齐全。
10|迁移 Redis、Supervisor 和 MQTT 配套环境
执行位置:新机。先安装、配置,业务消费者暂不启动。
Redis 是否本机迁移按旧部署决定。队列、会话与缓存先分类:会话可按客户约定重新登录,待执行队列和去重状态不能直接当缓存丢弃。正式停写后再迁需要保留的持久数据;不要把两套系统的 Redis 前缀合并。
Redis、Supervisor优先使用同版麒麟受控 RPM/wheel:
yum --disablerepo='*' install /workspace/cac-packages/redis-rpms/*.rpm
python3 -m pip install --no-index \
--find-links=/workspace/cac-packages/python-wheels \
/workspace/cac-packages/python-wheels/supervisor-已验收版本-py2.py3-none-any.whl
没有本机 Redis 需求就不装服务端。配置保留旧认证和访问范围,限定内网/回环,不能默认裸露到公网。Supervisor 业务配置先放在不被 include 的待启用目录,待第 22 步启用。
MQTT按实际使用决定是否迁移:核对设备 TCP 端口、浏览器 WebSocket 端口、账号、ACL、Client ID、Topic、持久会话及 retained 消息。同一 Broker 可服务两套应用,但必须有明确的 Topic/租户隔离,不能复制相同 Client ID 让两实例互相踢下线。
有道笔记后续修订需要 WebSocket,不能只沿用早期 WITH_WEBSOCKETS=OFF。若旧客户确实使用 WebSocket,准备对应 libwebsockets 依赖。下面是从笔记保留的源码安装路线,版本仅在与发布清单一致时使用:
# 新机,先安装已准备的同版离线编译依赖
yum --disablerepo='*' install /workspace/cac-packages/mqtt-rpms/*.rpm
cd /opt/cac-install
tar -xzf /workspace/cac-packages/runtime/mosquitto-2.0.18.tar.gz
cmake -S mosquitto-2.0.18 -B mosquitto-2.0.18/build-cac -DWITH_WEBSOCKETS=ON
cmake --build mosquitto-2.0.18/build-cac -j4
cmake --install mosquitto-2.0.18/build-cac
按实际安装位置登记动态库,不向系统 /usr/lib64 盲目复制覆盖:
find /usr/local/lib /usr/local/lib64 -name 'libmosquitto.so*' 2>/dev/null
# 若实际在/usr/local/lib64,登记该目录
printf '%s\n' /usr/local/lib64 > /etc/ld.so.conf.d/cac-mosquitto.conf
ldconfig
ldd /usr/local/bin/mosquitto_sub
以原 MQTT 配置为基线保留认证及 ACL,不沿用笔记早期的匿名访问。新配置形态:
# /etc/mosquitto/mosquitto.conf;示例端口需与旧系统一致
pid_file /run/mosquitto/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
listener 1883
protocol mqtt
# 仅实际需要WebSocket时保留以下两行
listener 9001
protocol websockets
已有客户端使用 TLS 时同步证书和 TLS 监听配置,不降级为明文。口令文件、ACL 从旧机受控迁移;若新建,mosquitto_passwd -c 只用于尚不存在的口令文件,已有文件新增用户不得带 -c。
id mosquitto || useradd -r -s /sbin/nologin mosquitto
install -d -o mosquitto -g mosquitto -m 750 /var/lib/mosquitto /var/log/mosquitto
install -d -m 750 /etc/mosquitto
# 恢复passwd和acl后核对权限,不输出其内容
chown root:mosquitto /etc/mosquitto/passwd /etc/mosquitto/acl
chmod 640 /etc/mosquitto/passwd /etc/mosquitto/acl
源码安装的新服务放 /etc/systemd/system/mosquitto.service;若已有发行版服务,先检查并复用,不能叠装:
[Unit]
Description=CAC Mosquitto Broker
After=network.target
[Service]
Type=simple
User=mosquitto
Group=mosquitto
RuntimeDirectory=mosquitto
RuntimeDirectoryMode=0755
ExecStart=/usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
RuntimeDirectory 解决 /run 重启后丢失的问题。新 Broker 仅在隔离测试网段启用,不能让正式设备同时接入新旧 Broker。用批准的专用测试 Topic 进行发布订阅,并实际测 WebSocket 连接;只看端口监听不等于协议通过。
11|把备份恢复到临时 MySQL
执行位置:独立迁移机/隔离 MySQL。不是旧生产库,也不是达梦。
分别准备匹配源版本的 MySQL 5.6、MySQL 8。使用演练机器或专用隔离实例,关闭 event_scheduler,不启动业务程序和复制链路。客户正式新机不必长期安装 MySQL。
# 用临时实例专属连接配置;defaults-extra-file放在第一个参数
/实际MySQL56/bin/mysql --defaults-extra-file=/受控路径/stage56.cnf \
-e 'SELECT @@hostname,@@port,VERSION();'
/实际MySQL8/bin/mysql --defaults-extra-file=/受控路径/stage8.cnf \
-e 'SELECT @@hostname,@@port,VERSION();'
管理员核对确为临时实例后关闭事件调度,再导入:
SET GLOBAL event_scheduler=OFF;
/实际MySQL56/bin/mysql --defaults-extra-file=/受控路径/stage56.cnf \
< /受控备份目录/front.sql > /受控记录目录/restore56.log 2>&1
echo $?
/实际MySQL8/bin/mysql --defaults-extra-file=/受控路径/stage8.cnf \
< /受控备份目录/foodsafe.sql > /受控记录目录/restore8.log 2>&1
echo $?
备份内含 USE/CREATE DATABASE,不能仅靠命令末尾库名防止导错。导入失败时保留错误和当前状态,不加 --force 跳过。处理 DEFINER/权限问题要生成审核后的副本,原 dump 与哈希保留。
通过标准:四库恢复完整;记录每表精确 COUNT(*)、结构、索引、触发器、事件、例程、字符集及 SQL_MODE。information_schema.TABLES.TABLE_ROWS 对 InnoDB 可能是估计,不能替代精确行数。
12|在临时库执行逐库版本升级
执行位置:临时 MySQL;先升级结构和必要业务数据,再迁达梦。
两份用户指定脚本已核对:
| 原脚本 | 本次使用要求 |
|---|---|
| store/db/init/zywxb/zywxb.sql | 现有目标为 zhct_wxbfcl,针对特定结构差异;有大量建表、字段修改、主键调整,按 zhct 和 zhct2 实际基线分别审核,不盲目重跑 |
| food_safety/db/upgrade/zywxb.sql | 当前目标 foodsafe2;同时含 USE 和 DATABASE()断言;用于foodsafe第一套前先重新比对结构,不只替换一个库名 |
菜单、参数、字典、权限等版本数据升级需单独确认,不把“结构一致”当成“版本升级全部完成”。
操作顺序:复制原脚本 → 标记目标库和版本 → 检查 USE、断言及所有跨库引用 → 编号分段 → 保存 SHA256 → 在临时库执行并逐段回读。
sha256sum /受控升级包/zhct-reviewed.sql
# foodsafe2示例;MySQL8脚本含DELIMITER,使用mysql客户端整份脚本方式
/实际MySQL8/bin/mysql --defaults-extra-file=/受控路径/stage8.cnf \
--show-warnings --binary-mode=1 foodsafe2 \
< /受控升级包/foodsafe2-reviewed.sql \
> /受控记录目录/foodsafe2-upgrade.log 2>&1
echo $?
每个库执行后检查新增表/列/索引、约束及必要初始化数据。错误即停,记录已经成功的段,不把整份脚本重复执行。MySQL DDL自动提交,外层事务不能替代恢复备份。
升级完成再导出四库的升级后快照,登记“升级前基线 → 升级脚本 → 升级后基线”。达梦迁移对账以升级后的临时 MySQL 为源,允许的新增数据必须有解释。
通过标准:四库分别标记“升级并核验”或“核验无需升级”;zhct和zhct2必须均有升级或无需升级结论后才进入正式停机。
13|在达梦准备四组业务目标
执行位置:新机达梦管理工具/disql,由数据库管理员执行。
演练使用独立演练目标,正式目标使用第 01 步映射。演练对象和正式对象不要混用;表空间目录与大小让厂家根据迁移后容量、索引和增长量确定,不能四个库都机械分配同一大小。
先查已有对象(管理账号):
SELECT USERNAME, DEFAULT_TABLESPACE FROM DBA_USERS
WHERE USERNAME IN ('ZHCT_APP','ZHCT2_APP','FOODSAFE_APP','FOODSAFE2_APP');
SELECT TABLESPACE_NAME FROM DBA_TABLESPACES
WHERE TABLESPACE_NAME IN ('ZHCT_TBS','ZHCT2_TBS','FOODSAFE_TBS','FOODSAFE2_TBS');
如果视图列与安装版本不同,由厂家提供等价查询;不要因查不到视图就认定对象不存在。
单组创建模板如下,仅在管理员确认目标不存在、填好路径/容量/密码后执行;其他三组对应替换,不保留示例密码:
-- 数值单位按当前版本确认,以下2048MB只是语法示例,不是四库统一容量建议
CREATE TABLESPACE "ZHCT_TBS"
DATAFILE '/CHANGE_ME_APPROVED_DATA_DIR/ZHCT_TBS.DBF'
SIZE 2048 AUTOEXTEND ON NEXT 128 MAXSIZE 32768;
CREATE USER "ZHCT_APP" IDENTIFIED BY "CHANGE_ME_PRIVATE_PASSWORD"
DEFAULT TABLESPACE "ZHCT_TBS"
DEFAULT INDEX TABLESPACE "ZHCT_TBS";
GRANT CREATE SESSION TO "ZHCT_APP";
-- 迁移建对象阶段如需RESOURCE,单独授予;生产运行权限按实际对象和调用复核
GRANT RESOURCE TO "ZHCT_APP";
不授 DBA,不把四库导入 SYSDBA/MAIN。角色与系统权限分开执行。账号密码从私有渠道注入,SQL实际执行副本仅保存在受控目录;DDL模板中的自动扩展上限必须重算,容量不够不能忽略告警继续。
通过标准:每个用户能登录自己的模式,默认表空间及索引表空间正确,不获无关模式访问权。前厅两套Store分别访问自己的单一业务模式,避免用全局跨模式授权代替正确配置。
14|执行四库 MySQL → 达梦迁移
执行位置:隔离迁移环境连接临时 MySQL 和已核准达梦目标。
本项目已有两种路径:官方 DTS 和 Codex 生成的迁移程序。选在演练中通过的一种,正式阶段使用同一冻结版本。
DTS操作顺序:打开达梦迁移工具 → 新建工程/迁移 → “其他数据库迁移到达梦” → “MySQL → DM” → 源端选择临时 MySQL 的一个库 → 目标端使用该库对应业务账号 → 核对目标模式 → 选择对象 → 审核类型映射 → 转换/迁移 → 查看每项成功、失败明细。四个库分别建立任务,不能复用上一库账号忘记切换。
MySQL 5.6 与 8 的源端 JDBC 驱动按各自版本选择;DTS 的 Java 驱动与 PHP/Node 应用驱动是两回事。新建模式已存在时,不让向导再次创建同名模式,也不选择覆盖未知表。
Codex操作顺序:提供四库升级后 dump、哈希、原版本、目标模式、应用版本与厂家参数 → 在隔离环境恢复源 → 生成逐列映射和分阶段迁移包 → 人工审核范围 → 演练导入 → 独立对账。最终客户 dump尚未提供,因此本手册不伪造一个“现在可直接运行”的通用迁移脚本。
迁移包应包含:建表、导入数据、普通索引、外键/注释、特殊对象、核验及恢复说明,分别编号并标注目标。主键/唯一约束支撑索引与普通索引分开,避免重复创建;数据导完后检查外键是否仍引用旧模式。
重点检查:字符长度与字节长度、unsigned、大整数与DECIMAL、零日期、空串和NULL、JSON/CLOB/BLOB、原自增值和下次取号、默认值、ON UPDATE、触发器、事件、视图、存储过程。客户历史值不能用开发库默认值补造。
本项目实测旧 PHP PDO_DM 对部分宽数值取回会丢精度,Node dmdb 某版本批量长字符串达到 32767 UTF-8字节可能截断。迁移程序必须使用经过验证的精确数值传输与长文本处理;不把数字先转float再格式化,不忽略单表错误。
通过标准:四个任务均无未处理失败,失败重试范围明确,源升级后快照没有被迁移程序修改。MySQL SQL不得直接喂给达梦执行。
15|独立核验四库数据
执行位置:迁移核验机;使用独立只读连接,不只相信导入日志。
逐库输出以下对照表,并保留在客户受控证据目录:
| 核验项 | 通过标准 |
|---|---|
| 表/列 | 与批准的升级后结构和类型映射一致,无漏表漏列 |
| 每表行数 | 源与目标精确COUNT一致,迁移过程新增的辅助对象单独列示 |
| 关键业务 | 人员、卡号、部门、订单、余额、充值、补贴、消费/退款汇总一致 |
| 精度与时间 | 最大ID、金额小数位、时间戳/日期语义一致,API返回类型符合原契约 |
| 大字段与文件 | JSON/CLOB/BLOB空值数、最大长度和样本摘要可比;图片路径对应实际文件 |
| 约束和自增 | 主键、唯一、启用外键正确;新增记录不会撞历史ID,关联写入正确 |
| 隔离 | 两套前厅、两套食安不串库;外键、程序连接和表空间均指向本组 |
源端计数示例:SELECT COUNT(*) FROM 已确认表名;;达梦用对应模式内的同一业务表。大表全表扫描安排在迁移窗口,避免在营业高峰临时全量对账。
表级完整比对和业务汇总应同时保留。中文、0/NULL/空串、历史边界值及下一次真实新增必须测试。迁移后统计信息收集由厂家按本实例和对象范围执行,再做代表性查询测速。
通过标准:全部差异为零或有业务负责人批准的升级解释。不能用“总行数相同”掩盖逐表错误,不能用“页面能打开”替代数据核验。
16|部署两套Store及各自客户配置
范围纠正:网信办前厅仅两套Store,数据库为zhct、zhct2。 本步骤旧版额外服务、数据库与双PHP要求已撤销。
详细操作以前厅独立手册第17—20步为准,包括操作位置、具体配置、成功标准和失败处理。PHP使用Store冻结版本,不因两套系统自动安装额外版本;两套站点、文件与任务分别核验。
17|食安按 dist 生产包部署两套
执行位置:制包机构建,新机只解压和运行。
制包必须使用已验收的达梦分支,不直接套用当前普通 standard。参考项目原有麒麟生产包,基本结构是:
foodsafe-release/
apps/web-school/dist/index.html
apps/web-regulator/dist/index.html
apps/screen/dist/index.html
apps/mobile-device/dist/index.html
services/gateway-service/package.json
services/gateway-service/dist/services/gateway-service/src/main.js
services/gateway-service/node_modules/ 或可解析的完整工作区依赖
node_modules/、libs/等运行时必需文件(按制包清单)
infra/nginx/
release-manifest.json
修正前述口头示例:此客户已验证生产包入口是 dist/services/gateway-service/src/main.js;当前普通分支脚本可能仍写 dist/main.js。必须核对冻结发布包的 scripts.start 与真实构建结果,不能仅以其中一个路径存在猜测版本。
制包机命令示例,按冻结分支唯一锁文件选择包管理器:
pnpm install --frozen-lockfile
pnpm --dir services/gateway-service run build
pnpm --dir apps/web-school run build
pnpm --dir apps/web-regulator run build
pnpm --dir apps/screen run build
pnpm --dir apps/mobile-device run build
每条构建退出码必须为0;历史材料中“tsc报错但有JS就继续”的做法不作为本次发布标准。独立端口站点通常以根路径发布;若使用子路径,先确认Vite实际支持的base/API配置并重新构建,不靠现场修改后端.env改变已编译前端。
离线包排除客户 .env*、data/、aiboxfile/、logs/、token、生产数据库文件。打包前必须在同版麒麟、同Node版本验证完整依赖;不要从Mac直接整体复制原生依赖。
新机先解压检查,再复制到两套新目录:
rsync -a --exclude='.git/' --exclude='.env*' \
--exclude='services/gateway-service/data/' \
--exclude='services/gateway-service/aiboxfile/' \
--exclude='services/gateway-service/logs/' \
/data/migration/staging/foodsafe-release/ /data/apps/foodsafe1/
# 第二套用已核对第二套端口/前端URL的包,不盲目把第一套配置复制过去
rsync -a --exclude='.git/' --exclude='.env*' \
--exclude='services/gateway-service/data/' \
--exclude='services/gateway-service/aiboxfile/' \
--exclude='services/gateway-service/logs/' \
/data/migration/staging/foodsafe2-release/ /data/apps/foodsafe2/
分别恢复两套根目录/服务目录 .env* 和运行文件,再切达梦连接。已有适配说明的配置字段为:
NODE_ENV=production
PORT=3300
DB_KIND=dm
DM_HOST=CHANGE_ME_DM_HOST
DM_PORT=5236
DM_USER=FOODSAFE_APP
DM_PASSWORD=CHANGE_ME_PRIVATE_PASSWORD
第二套为 PORT=3301、DM_USER=FOODSAFE2_APP。若发布版单独支持DM模式字段,按该版本真实配置设置;不凭空新增未被代码读取的参数。保留客户JWT/签名密钥、公共访问地址及设备配置。DM启动路径必须跳过MySQL迁移和种子;确认为DM后再启动,不能仅新增一个变量就认为旧MySQL配置不会生效。
先检查两个目录:
for root in /data/apps/foodsafe1 /data/apps/foodsafe2; do
for app in web-school web-regulator screen mobile-device; do
test -s "$root/apps/$app/dist/index.html" || exit 1
done
cd "$root/services/gateway-service" || exit 1
/opt/node/current/bin/node -p 'require("./package.json").scripts.start'
test -f dist/services/gateway-service/src/main.js || exit 1
/opt/node/current/bin/node -e 'for(const m of ["dmdb","tslib","@nestjs/core","dotenv","mqtt"]){require(m);console.log(m,"OK")}'
done
若正式产物入口有意变更,修改整套发布清单和下步PM2配置后再继续,不为让检查通过随意复制main.js。检查文件权限,确保foodsafe用户可读依赖和私有配置、可写本套data/aiboxfile/日志。
通过标准:8个前端dist齐全,两套后端入口、依赖、客户配置和数据均各自正确;没有把7月旧MySQL包冒充本次达梦版。
18|启动食安后端并配置八个前端入口
执行位置:新机;先在受限测试网络验证。
客户既有端口安排:
| 模块 | 第一套 | 第二套 | 监听进程 |
|---|---|---|---|
| 学校端 | 4201 | 4202 | Nginx |
| 监管端 | 4301 | 4302 | Nginx |
| 大屏 | 5209 | 5210 | Nginx |
| 移动端 | 4211 | 4212 | Nginx |
| 后端网关 | 3300 | 3301 | Node/PM2 |
PM2只管理两个后端,不再起8个前端dev进程。创建不含密码的 /data/apps/foodsafe-ecosystem.cjs:
module.exports = {
apps: [1, 2].map(n => ({
name: `foodsafe-${n}`,
cwd: `/data/apps/foodsafe${n}/services/gateway-service`,
script: 'dist/services/gateway-service/src/main.js',
interpreter: '/opt/node/current/bin/node',
instances: 1,
exec_mode: 'fork',
env: {NODE_ENV: 'production', PORT: n === 1 ? '3300' : '3301'},
out_file: `/data/app-logs/foodsafe${n}/out.log`,
error_file: `/data/app-logs/foodsafe${n}/error.log`,
merge_logs: true,
time: true,
autorestart: true
}))
};
以同一用户启动,明确运行路径:
runuser -u foodsafe -- env PATH=/opt/node/current/bin:/usr/bin:/bin \
/opt/node/current/bin/node /opt/pm2/node_modules/pm2/bin/pm2 \
start /data/apps/foodsafe-ecosystem.cjs
runuser -u foodsafe -- env PATH=/opt/node/current/bin:/usr/bin:/bin \
/opt/node/current/bin/node /opt/pm2/node_modules/pm2/bin/pm2 list
先通过发布版的任务开关关闭真实设备推送、MQTT订阅、演示任务、第三方同步;如没有可靠开关,使用网络隔离和专用测试端点。不要凭空填写并不被代码识别的开关。
Nginx使用同一个已安装服务,四端根目录分别指向对应dist。配套文件 Nginx模板 已包含两套8个入口和必要反代;它是配置模板,需要按实际Nginx目录安装,不会自动执行。
安装前先备份已有配置,并确认模板中的端口未被旧配置占用、两个upstream名称不重复;将模板复制为实际vhost目录内的cac-foodsafe.conf。例如LNMP:
NGINX=/usr/local/nginx/sbin/nginx
"$NGINX" -t
# 核对主nginx.conf的include,确认下列目录确实会被加载后再复制
install -m 644 /workspace/cac-packages/checks/foodsafe-nginx.conf.example \
/usr/local/nginx/conf/vhost/cac-foodsafe.conf
"$NGINX" -t
# 上条成功后才重载
"$NGINX" -s reload
项目旧配置的经验:普通HTTP的Connection映射使用空值 '' '',不要恢复成 '' close;/api/反代按原规则去前缀,/school/等保留前缀。WebSocket单独保留Upgrade。生产环境可按客户策略限制/api/docs,不因历史验证地址存在就要求公网开放。
for port in 4201 4301 5209 4211 4202 4302 5210 4212; do
curl --fail --silent --show-error -o /dev/null -w "$port %{http_code}\n" \
"http://127.0.0.1:$port/"
done
curl -i http://127.0.0.1:3300/health
curl -i http://127.0.0.1:3301/health
ss -lntp | grep -E ':(3300|3301|4201|4202|4301|4302|5209|5210|4211|4212)\b'
健康接口以发布包真实路由为准;如果不存在/health,使用已定义只读健康路由,不临时关闭认证。检查JS/CSS加载、刷新深层路由、实际登录API、中文及附件,避免SPA把错误API地址回成HTML 200。
后端当前代码可能监听所有网卡,不能只写“反代走127.0.0.1”就认为3300/3301已限制本机。以ss和防火墙实测为准;设备需要直连后端时仅放行设备网段,不对公网开放。
通过标准:两个PM2后端稳定online,八个前端由Nginx监听;业务API响应正确,没有Vite dev服务。整机重启验证在第23步执行。
19|完成迁移演练并确定停机窗口
执行位置:新机演练环境,客户代表参与。
前厅逐套验证登录、权限、人员/部门/卡务、余额/充值/补贴/消费/退款(按实际启用)、菜品配方、排菜订餐、营养计算、订单报表、异步导出、图片上传、设备/打印。食安逐套验证登录、食堂范围、人员/健康证、晨检/留样/消毒/农残/台账、图片/AI盒子、视频、大屏、报表及定时任务。
写测试只在隔离演练目标使用登记的测试账户和测试设备,不向真实支付/设备/消息接口发送指令。测试单据在最终迁移前隔离清除,不能带入正式目标。检查两套系统互不串库、串文件、串队列、串MQTT Topic。
记录:备份、传输、恢复、升级、导入、对账、文件同步、应用验证各耗时;用总耗时加现场余量确定停机窗口。不能根据两个磁盘dd数字推算整个迁移时间。
停机前确认:版本冻结、四库升级已演练、迁移零未解释差异、驱动精度问题已闭环、备份可恢复、网络切换方式确定、旧机回退路径可用、正式授权有效。任一核心问题未完成,先继续演练,不进入停写。
20|旧机正式停写并做最终备份
执行位置:旧机;从这里开始影响客户业务。
- 通知停机,记录截止时间;关闭客户写入口。
- 按第01步清单暂停旧机相应Cron、Supervisor任务、Workerman、队列、PM2后端、设备直连写入和MQTT消费者;先暂停会把它们拉起的watchdog。
- 等待在途交易结束,检查连接和订单,明确设备离线缓存如何保存及切换后补传。
- 确认四库业务写入停止,再做最终数据库及文件备份。
只停本项目清单中的进程,不能 pm2 stop all 或无范围停止整机Redis。Cron从备份副本编辑本项目行再装回,不能用空文件覆盖同事任务。
最终备份目录必须与演练分开:
umask 077
install -d -m 700 /backup/cac-migration/final
重复第04步,输出改为final。正式窗口全程维持停写,四库、文件、需保留的Redis队列和MQTT状态使用同一截止口径。更新校验和并传到受控迁移机。
文件最终同步先dry-run,核对来源是旧机、目标是新机对应目录,再执行:
rsync -an --itemize-changes /旧机实际上传目录/ 迁移账号@新机:/新机对应上传目录/
rsync -a --itemize-changes /旧机实际上传目录/ 迁移账号@新机:/新机对应上传目录/
不要直接使用--delete。新目录若残留演练文件,用演练清单准确隔离;禁止为“干净重来”删除未知客户目录。存在软链接、外部挂载或对象存储时按盘点结果分别处理。
通过标准:最终dump完整、文件同截止、在途和离线设备处理有记录,旧机继续停写且未做结构升级。
21|用最终备份重新完成正式迁移
执行位置:临时迁移机与新机达梦。
按第11—15步重新执行:干净临时MySQL恢复最终备份 → 冻结的逐库升级 → 最终达梦目标 → 独立对账。不能继续使用几天前的演练快照,也不能向演练库增量追加后假定一致。
正式目标若已有演练对象,数据库管理员根据归属和备份确认后处理;不得自动删除四个同名用户。新目标要确认没有夹具和测试交易。迁移失败保留错误及已完成阶段,按演练过的续跑或重建策略处理。
数据核验通过后,将四套应用配置从演练模式切为第01步正式模式。逐条确认主机、端口、用户名、模式、表前缀、Redis、文件目录,分别核对两个Store实际生效的database.php。停止旧PHP/Node进程后按新配置重启,清除新应用必要缓存,避免连接池仍连演练库。
通过标准:每个业务进程实际连接正确的正式模式;正式数据和文件核验通过;尚未开放广泛业务写入前完成只读验收。
22|切换入口、设备和后台任务
执行位置:新旧机及客户网络管理端。
按事先选定的一种方式切换:域名/代理/NAT改到新机,或在旧机释放IP后让新机接管。不得两机同时使用同一IP。保留旧机管理地址,防止回退时无法登录。
网络管理员按访问来源放行:客户业务网段到前厅和食安前端;设备网段到实际设备API/MQTT/视频端口;运维网段到SSH和必要管理入口。达梦、Redis不因排障而全网放行。
如果现场使用正在运行的firewalld,可按已审批网段逐条添加规则。下面仅示例食安前端,不包含设备后端或数据库端口:
ZONE=CHANGE_ME
BUSINESS_CIDR=CHANGE_ME
[ "$ZONE" != CHANGE_ME ] && [ "$BUSINESS_CIDR" != CHANGE_ME ] || exit 1
firewall-cmd --state
firewall-cmd --get-active-zones
# 先核对ZONE确实包含业务网卡;保留现有规则,不清空
for port in 4201 4301 5209 4211 4202 4302 5210 4212; do
firewall-cmd --permanent --zone="$ZONE" --add-rich-rule="rule family=ipv4 source address=$BUSINESS_CIDR port port=$port protocol=tcp accept" || exit 1
done
firewall-cmd --reload
firewall-cmd --zone="$ZONE" --list-rich-rules
前厅端口、设备3300/3301、MQTT和视频按登记表单独配置来源范围;IPv6启用时单独核对策略。已有全网放行规则不会因增加一条受限规则而自动失效,必须由网络管理员审查最终有效规则。若使用其他防火墙,不同时启用另一套管理器。
核对设备、回调、前端编译URL、二维码地址、文件域名、视频取流和白名单。第二套历史生产包中部分端口曾在源码/构建产物中写死,不能只改PORT=3301就认为全部切好;客户端Network和实际二维码逐个验证。
依次恢复:新机后端 → 小范围用户/测试设备验收 → 正式设备接入 → 新机业务队列/定时任务 → watchdog。每项启用前确认旧机对应项已停。设备补传核对交易唯一号和重复处理结果,确保不重复扣款或重复记账。
通过标准:真实访问落到新机;旧机不再写;两套前厅及两套食安分别完成一个真实业务闭环并对账。真实支付/退款测试使用客户批准的方式和金额,不把演练数据当真实业务证据。
23|设置开机恢复、备份、日志和观察
执行位置:新机;正式对外开放前尽量完成重启演练。
保存食安PM2进程,统一用户;不要root保存一套、foodsafe运行另一套:
runuser -u foodsafe -- env PATH=/opt/node/current/bin:/usr/bin:/bin \
/opt/node/current/bin/node /opt/pm2/node_modules/pm2/bin/pm2 save
# 管理员注册启动服务,固定Node路径和foodsafe家目录
env PATH=/opt/node/current/bin:/usr/bin:/bin \
/opt/node/current/bin/node /opt/pm2/node_modules/pm2/bin/pm2 \
startup systemd -u foodsafe --hp /var/lib/foodsafe
systemctl status pm2-foodsafe --no-pager
若命令输出额外安装命令,检查仍是上述Node路径和用户后执行。查看systemctl cat pm2-foodsafe,确保服务不依赖不存在的nvm路径。后续更新Node要重新核对PM2启动路径。
Cron/Supervisor使用绝对PHP路径和第08步的达梦环境。已有watchdog迁移后必须更新新目录、新用户、生产启动命令和两套端口,防止重启旧路径或拉起Vite dev。
日志设置轮转和保留周期,尤其PM2、Nginx、PHP和临时导出;按客户保留要求操作,不让日志挤满数据库所在盘。厂家实例级全备/增备/归档策略按现状核实成功记录,补充四模式逻辑导出及异机副本;单模式恢复与实例恢复分别演练。
观察至少覆盖一个完整就餐高峰和食安设备上报周期。检查CPU、内存、磁盘余量、IO等待、慢SQL、错误率、队列积压和归档增长。核对余额、订单与食安记录新增情况。
约定窗口重启新机,复验:达梦、Store PHP、Nginx、Redis、PM2、MQTT、Supervisor、Cron、watchdog自动恢复;/run目录重建;两套食安8个入口、2个前厅Store入口、设备和中文数据均正常。
通过标准:重启可恢复、无重复任务、备份可恢复、关键数据对账正常,客户确认观察结果。
24|回退与交接
回退前先停止新机写入、后台任务和设备处理,保全新机数据与日志。
| 状态 | 回退操作 |
|---|---|
| 新机尚无正式新增业务 | 停新机应用及任务;将入口/设备地址切回旧机;确认旧MySQL与旧代码仍是原版本;恢复旧机任务;验证业务 |
| 新机已有正式新增业务 | 先停写,记录差异时间窗;保全达梦、文件、队列和设备补传状态;按批准的数据补回/对账方案处理新增记录,再决定切回,不能直接丢弃新机交易 |
| 只有新代码故障但数据正确 | 在确认旧应用版本兼容当前达梦结构的前提下评估代码回退;不能简单换回原MySQL版代码仍连接达梦 |
不在故障现场立即删除达梦模式或迁移证据。旧机保留到约定观察期结束与客户验收后,再安排下线。
交接清单:四套访问入口、四库映射、发布版本与SHA、运行环境/驱动版本、实际配置位置、运行用户、服务与任务清单、文件目录、数据核验表、设备联调结果、备份及恢复记录、回退负责人。密码和授权文件通过私有渠道交接。
附录A|常见问题按这个顺序查
| 现象 | 先检查 |
|---|---|
| PHP提示could not find driver | 对应PHP版本、实际ini、PDO_DM是否加载;不是只看另一版本CLI |
| Unable to start DM module | ABI/架构、ldd依赖、FPM服务LD_LIBRARY_PATH、目录访问权限 |
| 中文乱码/JSON编码失败 | DM_SVC_PATH、CHAR_CODE、FPM池环境、真实中文数据读取 |
| 网页正常但Cron报错 | cron用户、绝对PHP路径、独立php-cli.ini、DM环境变量 |
| 食安Cannot find module tslib/dmdb | 完整运行依赖、pnpm链接目标、同架构包;不要现场逐个补到不知版本 |
| 食安Cannot find main.js | package.json scripts.start与真实dist目录不一致 |
| 食安HTTP 200/400交替 | Nginx Connection map、keepalive、直连与反代对照;采用已验证空值映射 |
| 登录正常但第二套数据不对 | 4个模式映射、两个Store数据库连接、PM2遗留环境、.env加载优先级、Redis前缀 |
| 食安页面200但接口返回HTML | /api代理路径、前缀剥离、SPA兜底错误;查响应Content-Type |
| MQTT重启失败 | RuntimeDirectory、运行用户、持久目录权限、libmosquitto动态库、WebSocket编译能力 |
| 迁移长文本截断 | 源最大UTF-8字节数、目标容量、dmdb批次绑定;按已验收长文本路径处理 |
| 金额/大ID显示异常 | 同时查数据库原值与PHP/Node取型,不从已失真float反推 |
| 文件404 | 实际文件是否迁到对应实例、旧绝对路径/URL、Nginx映射、权限、对象存储连通性 |
附录B|本次对有道笔记的采用与修正
已读取用户指定的有道笔记《麒麟操作系统服务器》,标题及正文已核验。原笔记包含敏感配置,本页面不复制原文或提供其外链。保留其Node20、PM2、Mosquitto编译、WebSocket和RuntimeDirectory经验;具体取舍如下:
| 笔记内容 | 本次手册处理 |
|---|---|
| nvm在线安装与默认node20 | 离线包锁定Node20精确版本;systemd明确路径,避免依赖登录shell |
| 新机安装MySQL8 | 达梦是正式目标,MySQL仅临时恢复/升级,不新装为正式业务库 |
| MySQL全局授权 | 不采用;四个DM业务账号按模式最小授权 |
| 前端/后端pm2 run dev | 全部改为生产dist;PM2仅守护两套编译后后端 |
| 旧目录/workspace/wwwroot | 本次应用迁到/data;不照搬其他服务器的IP、密码和目录 |
| MQTT先匿名,后补认证 | 保留客户有效认证与ACL,隔离演练;不启用匿名生产Broker |
| libmosquitto复制进系统lib64 | 按实际安装目录登记动态库,保留正确符号链接,不覆盖系统库 |
| 早期关闭WebSocket | 以实际设备/前端需要为准;需要则编译支持并验证9001等实际端口 |
| 全面放行端口 | 按业务/设备/运维来源网段放行,不默认公网开放 |
| 手工补/run/mosquitto | 改为systemd RuntimeDirectory,重启复验 |
附录C|依据与核验边界
- 用户确认:前厅两套、食安两套;旧机MySQL5.6/MySQL8;新机麒麟且厂家已装达梦;应用部署优先/data;要求dist生产包和在线实施手册。
- 厂家《数据库实施报告-网信办-前厅排菜系统-20260923》及运维、安装、系统管理、作业手册。只采用脱敏结论,不上传原件、账号、授权文件或截图。
- 官方MySQL迁移流程、用户与模式、PHP驱动问题、Node.js驱动。厂商示例不替代本次目标参数核实。
- 项目协作中的前厅LNMP、Store PHP、无数据库服务端安装路线、部署包契约及DM驱动实测。
- 食安2026-07-24/25原始麒麟生产部署交接、第二套生产包记录、Nginx反代配置、后续生产验收记录,结合当前代码核对。历史MySQL包仅作部署结构依据,不作为当前达梦版本。
- Mosquitto配置说明、PM2启动恢复。仅用于相关配置语义,不引入未经现场验证的新版本。
文档核验范围:已核对项目代码/历史部署产物和来源,检查文档与配置模板;没有连接客户服务器、执行安装、迁库或真实交易。当前正在进行的应用适配验收不能被本文替代。最终放行以第19—23步实际结果为准。