一、场景

基于公司业务需要,需要将集控站上云,集控站里面主子站很多,点位也很多。

二、问题出现

由于采用微服务开发,在接站操作中,是从A 服务导入文件,解析过程在B 服务, 刚开始自己调试的小工程没有任何问题。实际使用到了现场的工程一百多兆,点位有60万点,然后就出现了如下错误信息:

{ "status": 500, "code": 500, "success": false, "data": "java.net.SocketTimeoutException: Read timed out\n\tat java.net.SocketInputStream.socketRead0(Native Method)\n\tat java.net.SocketInputStream.socketRead(SocketInputStream.java:116)\n\tat java.net.SocketInputStream.read(SocketInputStream.java:171)\n\tat java.net.SocketInputStream.read(SocketInputStream.java:141)\n\tat org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)\n\tat org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)\n\tat org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)\n\tat org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)\n\tat org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)\n\tat org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)\n\tat org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)\n\tat

刚开始还没细看,以为是前端超时时间不够导致的,后台才发现是 A 服务通sdk 接口调用B服务的接口超时了,看了一下工具类里面的源码,超时时间设置的是一分钟

private static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig.custom()
        .setSocketTimeout(TIMEOUT)
        .setConnectTimeout(TIMEOUT)
        .setConnectionRequestTimeout(TIMEOUT)
        .build();

由于厂文件很大,以为是这个文件传输耗时,就将超时时间先改为了30分钟, 后续这个错误不出现了,但是就是一直没有返回卡在那里,也没有错误日志输出。

中间零星几次调试偶尔还出现了:

org.eclipse.paho.client.mqttv3.MqttException: 已断开连接
    at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:197)
    at java.lang.Thread.run(Thread.java:750)
Caused by: java.io.EOFException: null
    at java.io.DataInputStream.readByte(DataInputStream.java:267)
    at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92)
    at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:137)
    ... 1 common frames omitted
com.alibaba.druid.pool.DruidDataSource {conn-10001} discard
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet successfully received from the server was 10,010 milliseconds ago. The last packet sent successfully to the server was 10,010 milliseconds ago.
    at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)
    at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354)
    at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3446)
    at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:434)
    at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3444)
    at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.execute(PreparedStatementProxyImpl.java:158)
    at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:483)
    at sun.reflect.GeneratedMethodAccessor91.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:58)

当时也不知道怎么回事,还以为是文件太大了,那里有限制卡主了,然后就误入歧途(其实中间问了豆包,给了解释说,文件传输不会有单独的限制),开始将文件流的传输,改为传路径,然后开始了文件的调试, 其中又因为路径中带有中文, 经过SDK接口传输后,编码不统一,导致了路径变了,找不到文件,反正一顿折腾,时间又一下子耗完了,每次调试又是这种大文件,要好久。

每次都是调试转换到第二个子站的时候出问题,这个时间问了一下组长, 刚开始说给mysql 对应的额表加索引,好像确实有点效果,但是后面还是卡主了。
 

最后看了一下卡顿时的日志,有个数据查询,显示查询有20万条记录,此时才找到问题点。

原来是操作的数据库记录太多了,随后从这个口子开始突破,修改查询逻辑,最终通过了。

但是在二次导入时,又出现了,这次是一次删除太多了,又问了豆包,给出了分片分批删除的代码:

@Service
public class FacDeviceAttrService {

    private static final Logger log = LoggerFactory.getLogger(FacDeviceAttrService.class);

    @Resource
    private FacDeviceAttrMapper facDeviceAttrMapper;

    private static final int BATCH_SIZE = 2000; // 批次大小:1000-2000 条(数字+下划线 ID 适配)

    public int batchDeleteByProjectId(String projectId) {
        int totalDeleted = 0;
        String lastId = ""; // 初始空字符串(字典序最小,覆盖所有符合条件的 ID)

        while (true) {
            // 查询当前批次 ID 列表(数字+下划线 String ID 直接用 gt 字典序比较)
            LambdaQueryWrapper<FacDeviceAttr> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(FacDeviceAttr::getProjectId, projectId)
                        .gt(FacDeviceAttr::getId, lastId) // 关键:字典序比较,适配数字+下划线
                        .orderByAsc(FacDeviceAttr::getId) // 确保排序一致,避免遗漏
                        .last("LIMIT " + BATCH_SIZE);

            List<String> idList = facDeviceAttrMapper.selectIdListByWrapper(queryWrapper);
            if (idList.isEmpty()) break;

            // 批量删除
            LambdaQueryWrapper<FacDeviceAttr> deleteWrapper = Wrappers.lambdaQuery();
            deleteWrapper.in(FacDeviceAttr::getId, idList);
            int deleted = facDeviceAttrMapper.delete(deleteWrapper);
            totalDeleted += deleted;

            // 更新 lastId(取当前批次最后一个 ID)
            lastId = idList.get(idList.size() - 1);

            // 批次间休眠减压
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("分批删除中断,已删除 {} 条", totalDeleted, e);
                throw new RuntimeException("删除中断", e);
            }

            log.info("删除进度:projectId={},已删 {} 条,当前批次 {} 条,最后 ID={}",
                    projectId, totalDeleted, deleted, lastId);
        }

        log.info("删除完成:projectId={},总计删除 {} 条", projectId, totalDeleted);
        return totalDeleted;
    }
}

果然只要方向对了,用上AI ,还是可以加快调试速度的。

三、总结

方向很重要,结合大模型,提供有效信息,并且顺着其给出的思路去分析。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐