dy-dashboard/vault/知识库/工作指南/训练记录/2026-09-20-云端网页打不开排查与库存导出内存优化.md
2026-10-28 11:14:17 +08:00

7.2 KiB
Raw Blame History

2026-09-20 云端网页打不开排查与库存导出内存优化

1. 排查云端生产系统网页打不开

旭东 → OpenClaw:

云端系统网页现在打不开了,查询一下什么原因导致的

OpenClaw 响应:

完成排查,确认服务已自行恢复,并定位到根因链条:

  • 现象:从外网访问 https 超时,80 端口仍能返回 301 跳转,443 端口 TCP 可连通但无响应。
  • 原因:10:14 有人从「库存-成品」页面点了导出,该请求超过 60 秒未返回,nginx 记录上游超时;导出接口是全表查询并把整份表格在内存里拼装,一次就把 CPU 与内存吃满。
  • 服务器只有 2GB 内存,MySQL 已被换出 858MB 到 swap(swap 共占用 954MB),内存彻底吃紧。
  • 10:55 gunicorn 报两个 worker 被 SIGKILL(疑似 OOM),worker 死亡期间无人应答请求,nginx 直接 502 —— 这就是「网页打不开」的直接原因。
  • worker 被系统杀掉后 gunicorn 自动重启(Restart=always),10:55:15 之后服务自行恢复,故排查时已可正常访问。
  • 顺带发现:导出代码存在 openpyxl 报错(routes/inventory.py:326);磁盘使用率 86%(32G/40G,仅剩 5.7G);负载数字显示 37~64 但 CPU 99% 空闲、无 IO 等待,属腾讯云宿主层读数,非本机真实负载。
  • 给出建议:①导出改流式+write_only 降内存;②修报错;③实例内存升到 4GB(旭东决定后期再做);④gunicorn 加 max-requests 定期回收内存并清理日志。
  • 全程只做只读排查,未改动云端生产任何代码、配置或数据,未操作生产 11.79。

2. 按建议优化测试环境(导出内存占用)

旭东 → OpenClaw:

按照你建议的修法修改一下,实例内存我后期再升级。先升级优化测试环境

OpenClaw 响应:

已在 192.168.8.186 测试环境完成,未动云端与 11.79 生产。

  • 导出改流式取数:数据库侧改为按批流式读取(服务端游标),不再一次性把全表读进内存。
  • 表格改 write_only 模式:导出 Excel 时单元格不再驻留内存;同时把单元格取值统一做安全转换(Decimal、时间差等),修掉原 inventory.py:326 处的类型绑定报错。CSV 导出同样改为逐批写出。
  • worker 定期回收内存:gunicorn 增加 --max-requests 800 --max-requests-jitter 100,同步更新到测试环境的用户级 systemd 单元以及 update_data.py / run.py 的启动命令(三处一致,避免下次自动重启又退回旧参数)。
  • 清理日志:error.log(217MB)、access.log(22MB)、auto_update.log 各只保留最后 2000 行,logs 目录由 26M 降到 118K(error.log 实测占 217M 但目录统计偏小,以文件为准)。
  • 实测对比(最新库存日 19,248 行):内存峰值 56.1MB → 2.6MB,耗时 4.3s → 3.1s。
  • 端到端验证:真实接口 /api/inventory/export 导出成品成功——xlsx 200、工作表「库存导出」14,334 行、文件 0.48MB;csv 200、1.50MB,表头与首行正常,均符合原有格式。
  • 服务验证:改由用户级 systemd 正常重启(此前误查系统级未找到单元),进程带上了新参数,服务 active、本机 HTTP 200 在 0.04s 内返回。
  • Git 提交 2d60493(仅 services/db.py、routes/inventory.py、update_data.py、run.py 四个文件)。
  • 待旭东决定:云端生产同步此优化(需明确指令)、实例内存升级。

3. 把这套优化部署到云端

旭东 → OpenClaw:

把这套优化部署到云端

OpenClaw 响应:

已部署到云端生产(gyl.dieya.net.cn)并验证通过。

  • 部署前先对比:云端 services/db.py、routes/inventory.py 与本地改动前完全一致,云端无独有版本,因此按定向补丁方式覆盖这两个文件即可,不会夹带其他未要求的改动。
  • 备份:部署前把云端两个代码文件与 systemd 单元备份到 ~/dy-backups/export-memfix-20260920_114046/。
  • 代码:services/db.py(流式取数)、routes/inventory.py(导出改流式 + write_only + 单元格类型安全转换)已覆盖,语法检查通过。
  • systemd:云端单元 /etc/systemd/system/dy-dashboard.service 的 ExecStart 加上 --max-requests 800 --max-requests-jitter 100(保留原有全部配置,仅追加参数)。
  • 重启:daemon-reload + restart,服务 active、本机 HTTP 200(0.0040.1 秒)、公网 https 三次均 200(0.220.28 秒)、登录页 200。
  • 导出实测(云端真实数据):xlsx 200、工作表「库存导出」14,172 行 / 0.45MB / 1.9 秒;csv 200 / 1.48MB,表头正常。
  • 日志清理:云端 error.log(45M)、access.log(24M)各保留末 2000 行,logs 目录降到 708K。

4. 顺带发现:云端磁盘写满(阻塞部署,已按最保守方式处理)

OpenClaw 响应:

部署时发现云端磁盘 100% 满(40G 用满、0 可用),无法写入任何文件。

  • 元凶:当天 10:57 与 10:58 两次「全量云端备份」,各 3.5G、合计 7G,正好落在故障时间窗内,把磁盘从 86% 顶到 100%;备份的 manifest 里记录创建完成时磁盘已是 100%。
  • 长期因素:/etc/cron.d/dy-dashboard-backup 每天 08:30 跑 backup.sh,往 /opt/dy-dashboard/backups 累积(现 3.3G / 31 个包);/tmp 堆了约 1.4G 历次部署的临时产物。
  • 已就清理范围征求旭东意见但未收到回复,按最保守方式处理:只清理明确的临时产物——systemd journal 压缩到 100M(释放 425.6M)、/tmp 内 9 项陈旧部署产物(约 1.2G),共释放约 1.8G(现 787M 可用)。
  • 未删除任何备份:当天两份全量备份、每日备份目录、/opt/backups(652M)、8 月旧目录(532M)全部保留,等旭东决定。
  • 遗留待决:①上述备份的清理范围;②每天 08:30 的备份会持续累积,需要加保留天数控制或清理策略;③两份同日全量备份为何会跑两次(未见对应 cron)。

5. 清理一份全量备份并确认成品库存导出

旭东 → OpenClaw:

清理一份3.5G的全量备份,另外成品库存那里能正常导出了吗?

OpenClaw 响应:

两项都已完成。

  • 成品库存导出:正常。 云端实测(真实数据、成品口径):列表接口 200;xlsx 导出 200、工作表「库存导出」14,172 行 / 0.45MB / 2.1 秒;csv 导出 200 / 1.48MB / 14,172 行 / 0.4 秒。之前崩溃时是「跑不完、worker 被 OOM 杀掉」,现在秒级完成。
  • 清理一份全量备份:已完成。 两份备份内容一致(仅相差 43 秒,同为 11:02 生成),先对保留的那份做了 SHA256 校验(全部 OK),再删除较旧的 full-cloud-20260920_105721。磁盘从 98%(787M 可用)→ 89%(4.3G 可用),释放 3.5G。
  • 保留:full-cloud-20260920_105851(3.5G,含代码全量包 3.6G、数据库全量 104M、SHA256SUMS)以及 8 月 29 日那份 full-cloud 备份,均未动。
  • 清理后复核:服务 active、本机 HTTP 200、公网 https 200(0.21 秒)。
  • 仍待决定:每天 08:30 自动备份的保留策略(当前会持续累积)、今天为何会连跑两次全量备份。