Skip to content

服务器云盘暴增排查与修复记录 ​

记录日期: 2026-08-20
影响范围: 服务器根分区、携岛开发实例及其日志;生产蓝绿实例未执行发布切换

1. 事件概述 ​

服务器云盘在 2026-08-19 下午出现磁盘 I/O 持续升高和磁盘空间快速增长。23:00 左右的服务器重启是人工执行的止损操作,不是问题的根因;重启后如果不处理任务和日志源,异常仍可能再次出现。

本次排查重点是确认是否由项目服务导致。证据表明,xiedao-dev.service 是本次异常的重要来源:开发实例的后台任务反复处理历史拼团订单,因缺少退款规则快照持续抛出异常,同时开启 MyBatis DEBUG SQL,形成大量日志写入和数据库查询。另有一个独立的 site_total.service 因可执行文件缺失,每 5 秒失败重启一次,也增加了 journald 日志噪声。

2. 排查证据 ​

2.1 磁盘与日志占用 ​

初始检查结果:

  • 根分区 /dev/vda3:40G,已使用约 31G。
  • /var/log/journal:约 3.8G。
  • /var/log/syslog:约 1.3G。
  • /opt/xiedao/dev/logs:约 1.2G。

配置生效并整理历史 journald 后,根分区约使用 28G(73%),journald 占用约 965MB;未手工删除应用业务日志。

2.2 I/O 与慢查询 ​

历史 sar 记录显示,约 16:50 至 23:04 持续出现:

  • 读取约 108MB/s。
  • 约 1600~1900 IOPS。
  • 磁盘利用率约 97%。
  • Java/MySQL 存在约 46~60 秒的慢 SQL。

修复后抽样 iostat -xz:

  • 磁盘 %util 约 1%~6%。
  • iowait 约 0.5%~2%。

2.3 应用日志与任务 ​

xiedao-dev.service 在旧启动期间产生约 73,511 条日志,主要特征为:

  • 大量 MyBatis DEBUG SQL,包括重复的定时任务查询。
  • 重复异常:订单缺少退款规则快照: MAIN:8577、订单缺少退款规则快照: MAIN:8598。
  • 异常发生在拼团超时处理路径,历史订单因缺少退款规则快照无法继续处理。

site_total.service 的可执行文件 /www/server/site_total/site_total 不存在,systemd 每 5 秒以 203/EXEC 失败并重启。

3. 根因判断 ​

3.1 主要原因 ​

开发实例的后台任务和日志配置共同放大了问题:

  1. 定时任务持续扫描到无法处理的历史拼团订单。
  2. 缺少退款快照导致同一业务异常反复抛出。
  3. com.xiedao 处于 DEBUG 级别,MyBatis 将每条 SQL、参数和结果写入日志。
  4. 任务查询和日志写入同时造成数据库 I/O、磁盘 I/O 和云盘使用量增长。

3.2 次要原因 ​

site_total.service 的失效重启循环持续向 journald 写入失败记录,属于独立的系统级日志放大源。

3.3 尚不能下结论的事项 ​

不能仅凭本次现象断定项目是云盘增长的唯一来源,也没有直接修改历史订单状态或手工插入退款快照。涉及已支付订单的状态变更可能触发微信退款,必须由业务人员核对后单独处理。

4. 已执行的服务器修复 ​

4.1 隔离开发实例的后台任务 ​

已备份并修改 /opt/xiedao/dev/env.sh:

bash
APP_SCHEDULING_ENABLED=false
SPRING_QUARTZ_AUTO_STARTUP=false
JAVA_OPTS 追加 -Dlogging.level.com.xiedao=INFO

两个开关的含义:

  • APP_SCHEDULING_ENABLED=false:关闭 Spring @Scheduled 任务。
  • SPRING_QUARTZ_AUTO_STARTUP=false:不启动 Quartz 调度器。

这只影响开发实例的自动任务,不关闭 HTTP 接口、数据库连接或普通业务请求。

4.2 限制 journald ​

已创建 /etc/systemd/journald.conf.d/xiedao-limits.conf:

ini
[Journal]
SystemMaxUse=1G
SystemKeepFree=2G
MaxRetentionSec=14day

已重启 journald,未执行额外的强制日志删除。

4.3 停止失效服务 ​

已执行:

bash
systemctl disable --now site_total.service

当前服务状态为 disabled、inactive,不再产生新的 203/EXEC 重启日志。后续应确认该服务是否仍有业务用途;若需要使用,应恢复正确的可执行文件和启动配置。

5. 已执行的代码修改 ​

5.1 日志保护 ​

文件:Api/ruoyi-admin/src/main/resources/logback.xml

  • com.xiedao 日志级别从 debug 调整为 info。
  • sys-info、sys-error、sys-all、sys-user 滚动日志均增加 totalSizeCap=1GB。

历史日志不会立即被删除,总容量限制会在后续日志滚动时生效。

5.2 缺少退款快照时降噪并隔离 ​

文件:Api/ruoyi-system/src/main/java/com/xiedao/system/service/impl/XdGroupServiceImpl.java

  • 对“订单缺少退款规则快照”进行识别。
  • 同一拼团只记录一次明确的 WARN,不再重复输出完整异常堆栈。
  • 暂停该拼团的超时处理,等待人工补齐退款规则快照后重试。
  • 不改变拼团状态,不自动发起退款。
  • 成功处理后移除告警去重标记。

5.3 测试 ​

新增测试确认同一拼团连续处理两次时只输出一次告警,并保留原有拼团超时和退款申请测试。

6. 构建、部署与验证 ​

针对性测试命令:

bash
cd Api
mvn -pl ruoyi-system -am \
  -Dtest=XdGroupServiceImplTest \
  -Dsurefire.failIfNoSpecifiedTests=false test

结果:4 个测试全部通过。

开发部署命令:

bash
cd Api
./deploy-dev.sh skip-tests

结果:

  • 开发发布成功,健康检查 http://127.0.0.1:8082/captchaImage 通过。
  • 第二次部署时开发数据库已处于最新迁移版本,无新增迁移。
  • 重启后的 xiedao-dev.service 日志中未发现新的 DEBUG、退款快照异常或 ERROR。
  • xiedao-dev.service 为 active/running。
  • site_total.service 为 inactive/disabled。
  • 磁盘 I/O 已从历史约 97% 利用率降至抽样约 1%~6%。

部署使用了 skip-tests,因此该工作区仍属于开发验证发布,不应直接视为生产可发布版本。

7. 生产环境状态 ​

生产 blue/green 两套实例均保持运行。对 2026-08-19 至当前日志进行检查,未发现同类退款快照异常或 DEBUG 日志暴增,因此本次没有直接修改生产实例,也没有切换生产流量。

生产发布前需要单独确认:

  1. 是否允许将日志级别和异常降噪代码发布到生产。
  2. 哪一套实例负责执行全局后台任务,避免 blue/green 重复执行。
  3. 历史订单缺少退款快照的业务处理方案,尤其是已支付订单。

8. 后续建议 ​

  1. 观察开发实例至少 1 小时,并持续记录 df -h、journalctl --disk-usage、iostat -xz 和应用异常计数。
  2. 为磁盘使用率、journald 占用、应用日志增长速度和 203/EXEC 服务失败次数配置告警。
  3. 对 MAIN:8577、MAIN:8598 等历史订单进行人工核对,确认退款规则来源和资金状态后再决定是否补数据或重试。
  4. 评估将后台调度从每个 blue/green 实例都启动,调整为单实例调度、分布式锁或明确的调度主节点。
  5. 日志总容量限制生效后,再评估是否按保留策略清理历史日志;清理前应先归档并确认审计要求。

9. 后续调度治理(代码已完成,待部署) ​

第 4.1 节记录的是事故止损时的服务器实际操作:当时 Spring @Scheduled 和 Quartz 都被关闭。后续代码治理不再把“全部关闭”作为开发环境常态,而是采用以下边界:

  • 有业务副作用的任务统一由 Quartz sys_job 管理;Spring @Scheduled 只保留微信履约 就绪检查和指标聚合。
  • 支付超时关单与微信查单补偿合并到 paymentExpireTask.run();退款状态同步与重试合并到 refundSyncTask.run(),删除两套重复扫描实现。
  • 新增迁移统一注册业务 Quartz Job,并暂停 RuoYi 示例任务。
  • 开发 profile 默认开启 Spring 调度和 Quartz,同时开启 app.scheduling.safe-mode;高风险 业务 Job 会注册到 Quartz 后保持暂停,可在后台查看并按需手动联调,不会自动执行。
  • 开发 profile 默认关闭微信发货同步和微信受管交易能力,避免自动调用外部生产能力。

代码配置的开发安全验证模式为:

bash
APP_SCHEDULING_ENABLED=true
SPRING_QUARTZ_AUTO_STARTUP=true
APP_SCHEDULING_SAFE_MODE=true
WX_SHIP_SYNC_ENABLED=false
WX_TRADE_MANAGED_ENABLED=false

本节代码尚未部署到服务器。/opt/xiedao/dev/env.sh 中事故止损时写入的 APP_SCHEDULING_ENABLED=false 和 SPRING_QUARTZ_AUTO_STARTUP=false 会覆盖 profile 默认值; 部署验证时需要同步改为上述安全验证配置,再检查 Quartz 注册、暂停状态和日志增长情况。

携岛 XieDao · 内部文档