编辑 | blame | 历史 | 原始文档

GPS分段里程计算任务超时问题修复说明

问题描述

GPS分段里程计算定时任务执行时出现数据库连接超时错误:

ERROR c.r.q.t.VehicleGpsSegmentMileageTask - GPS分段里程计算任务执行失败
java.lang.RuntimeException: 批量计算失败: 
### Error querying database.  Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet successfully received from the server was 60,022 milliseconds ago.

问题原因

  1. 数据库Socket超时配置过短socketTimeout: 60000(60秒),对于大数据量GPS查询处理不足
  2. 查询性能不佳:缺少必要的数据库索引,导致大表扫描耗时过长
  3. 错误处理不完善:单个车辆计算失败会影响整个批处理流程
  4. 缺少进度日志:无法了解批量处理的实时进度

解决方案

1. 增加数据库连接超时时间

修改文件
- ruoyi-admin/src/main/resources/application-dev.yml
- ruoyi-admin/src/main/resources/application-test.yml
- ruoyi-admin/src/main/resources/application-prod.yml

修改内容
yaml # 配置网络超时时间(从60秒增加到5分钟) socketTimeout: 300000

原因:GPS分段里程计算需要处理大量数据,60秒的超时时间不足以完成查询操作。增加到5分钟(300秒)可以避免正常查询被误判为超时。

2. 优化数据库索引

执行SQL文件sql/optimize_gps_query_performance.sql

关键索引
```sql
-- 组合索引:vehicle_id + collect_time
ALTER TABLE tb_vehicle_gps
ADD INDEX idx_vehicle_collect_time (vehicle_id, collect_time);

-- 单列索引:collect_time
ALTER TABLE tb_vehicle_gps
ADD INDEX idx_collect_time (collect_time);

-- tb_vehicle_gps_calculated表索引
ALTER TABLE tb_vehicle_gps_calculated
ADD INDEX idx_gps_id (gps_id);
ADD INDEX idx_vehicle_id (vehicle_id);
```

效果
- 大幅提升按车辆ID和时间范围查询的性能
- 优化活跃车辆查询速度
- 改善LEFT JOIN查询性能

3. 增强批处理错误处理

修改文件VehicleGpsSegmentMileageServiceImpl.java

改进点
1. 单车失败不影响全局:单个车辆计算失败不会中断整个批处理
2. 详细的进度日志:每处理10辆车输出一次进度
3. 成功/失败统计:记录成功和失败的车辆数量
4. 更详细的错误信息:包含堆栈跟踪,便于问题定位

代码改进
```java
int successCount = 0;
int failedCount = 0;

for (int i = 0; i < vehicleIds.size(); i++) {
try {
// 处理单个车辆
int segmentCount = calculateVehicleSegmentMileage(vehicleId, startTime, endTime);
if (segmentCount > 0) {
successCount++;
}
} catch (Exception e) {
failedCount++;
logger.error("计算车辆失败,但继续处理下一辆", e);
// 不中断批处理
}

// 进度日志
if ((i + 1) % 10 == 0) {
    logger.info("进度: {}/{}, 成功: {}, 失败: {}", ...);
}

}
```

部署步骤

1. 数据库优化(必须)

# 连接到MySQL数据库
mysql -u root -p

# 执行索引优化SQL
source sql/optimize_gps_query_performance.sql

# 验证索引创建成功
SHOW INDEX FROM tb_vehicle_gps;
SHOW INDEX FROM tb_vehicle_gps_calculated;

2. 应用配置更新(必须)

  1. 备份当前配置文件
  2. 更新配置文件中的socketTimeout参数
  3. 重启应用服务
# 停止服务
./ry.sh stop

# 启动服务
./ry.sh start

# 查看日志
tail -f logs/sys-info.log

3. 验证修复效果

  1. 手动触发定时任务
  • 登录后台管理系统
  • 进入【系统监控】->【定时任务】
  • 找到"GPS分段里程实时计算"任务
  • 点击【执行一次】按钮
  1. 查看执行日志
    ```bash

    查看GPS计算日志

    grep "VehicleGpsSegmentMileageTask" logs/sys-info.log

查看成功/失败统计

grep "批量分段里程计算完成" logs/sys-info.log
```

  1. 检查数据库
    ```sql
    -- 查看最新的分段里程记录
    SELECT * FROM tb_vehicle_gps_segment_mileage
    ORDER BY create_time DESC
    LIMIT 10;

-- 统计今日处理的车辆数
SELECT COUNT(DISTINCT vehicle_id) as vehicle_count
FROM tb_vehicle_gps_segment_mileage
WHERE DATE(create_time) = CURDATE();
```

性能监控建议

1. 定时任务执行时间监控

在定时任务管理中查看执行时长:
- 正常情况:每5分钟执行一次,处理10分钟数据,应在1-2分钟内完成
- 异常情况:超过3分钟需要关注,可能存在性能问题

2. 数据库慢查询日志

检查MySQL慢查询日志:
```sql
-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 启用慢查询日志(如果未启用)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
```

3. Druid监控

访问Druid监控页面:http://your-domain/druid/
- 用户名:ruoyi
- 密码:123456

关注指标:
- SQL执行时间
- 连接池使用情况
- 慢SQL列表

后续优化建议

1. 定期清理历史数据

GPS数据量大,建议定期清理历史数据:

-- 保留最近90天的GPS原始数据
DELETE FROM tb_vehicle_gps 
WHERE collect_time < DATE_SUB(NOW(), INTERVAL 90 DAY);

-- 优化表空间
OPTIMIZE TABLE tb_vehicle_gps;

可以创建定时任务每月执行一次。

2. 分批处理大量车辆

如果车辆数量超过1000辆,建议修改批处理逻辑,分批处理:

// 每批处理100辆车辆
int batchSize = 100;
for (int i = 0; i < vehicleIds.size(); i += batchSize) {
    List<Long> batchIds = vehicleIds.subList(i, 
        Math.min(i + batchSize, vehicleIds.size()));
    processBatch(batchIds);
}

3. 使用异步处理

对于特别耗时的操作,可以考虑使用异步处理:

@Async
public CompletableFuture<Integer> calculateVehicleAsync(Long vehicleId) {
    // 异步计算
}

4. 增加缓存机制

对于频繁查询的车辆信息,可以使用Redis缓存:

@Cacheable(value = "vehicleInfo", key = "#vehicleId")
public VehicleInfo getVehicleInfo(Long vehicleId) {
    return vehicleInfoMapper.selectVehicleInfoById(vehicleId);
}

相关文件清单

修改的文件

  1. ruoyi-admin/src/main/resources/application-dev.yml - 开发环境配置
  2. ruoyi-admin/src/main/resources/application-test.yml - 测试环境配置
  3. ruoyi-admin/src/main/resources/application-prod.yml - 生产环境配置
  4. ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsSegmentMileageServiceImpl.java - 批处理逻辑优化
  5. ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml - 添加SQL注释

新增的文件

  1. sql/optimize_gps_query_performance.sql - 数据库性能优化SQL

故障排查

问题1:执行SQL时报错"索引已存在"

解决方案
```sql
-- 删除已存在的索引
DROP INDEX idx_vehicle_collect_time ON tb_vehicle_gps;
DROP INDEX idx_collect_time ON tb_vehicle_gps;

-- 重新创建索引
-- 然后执行optimize_gps_query_performance.sql
```

问题2:修改配置后仍然超时

检查步骤
1. 确认配置文件修改生效:检查当前激活的profile(dev/test/prod)
2. 确认应用已重启:ps -ef | grep java
3. 查看Druid连接池配置:访问 /druid/ 检查socketTimeout值
4. 检查数据库服务器配置:SHOW VARIABLES LIKE 'wait_timeout';

问题3:索引创建后性能未改善

检查步骤
```sql
-- 1. 验证索引是否被使用
EXPLAIN SELECT DISTINCT vehicle_id
FROM tb_vehicle_gps
WHERE collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY);

-- 2. 更新表统计信息
ANALYZE TABLE tb_vehicle_gps;

-- 3. 检查表数据量
SELECT COUNT(*) FROM tb_vehicle_gps;
```

总结

本次修复主要解决了GPS分段里程计算任务的超时问题,通过以下措施:

  1. ✅ 增加数据库连接超时时间(60秒 -> 300秒)
  2. ✅ 添加数据库索引优化查询性能
  3. ✅ 改进批处理错误处理机制
  4. ✅ 增强日志输出,便于监控和问题定位

预期效果
- 任务执行不再超时
- 查询性能提升50%以上
- 单个车辆失败不影响整体处理
- 实时了解处理进度

注意事项
- 必须执行数据库索引优化SQL
- 必须重启应用使配置生效
- 建议定期清理历史GPS数据
- 持续监控任务执行情况