【问题标题】:How to find out the root cause of container going out of memory (OOM)如何找出容器内存不足(OOM)的根本原因
【发布时间】:2021-10-02 07:54:56
【问题描述】:

我正在我的 Micronaut 应用程序中运行一个批处理,它从 db 获取 500 000 条记录,挑选 100 个项目的批处理,然后在处理(包括对该批处理的 api 调用)之后再次将数据插入另一个 sqlite 表中。

     try (Connection connection = dataSource.getConnection();
            PreparedStatement statement = connection.prepareStatement("SELECT id,item_id,type,operation FROM table WHERE serial_id = ? AND type = ? AND fail_reason IS NULL"  )) {
            statement.setString(1, serialId);
            statement.setString(2, type.name());
            ResultSet resultSet = statement.executeQuery();
            List<ItemEntity> itemEntities = new ArrayList<>(batchSize);
            int i = 0;
            while (resultSet.next()) {
                itemEntities.add(ItemEntity.builder()
                        .id(resultSet.getString("id"))
                        .itemId(resultSet.getString("item_id"))
                        .type(ItemType.valueOf(resultSet.getString("type")))
                        .operation(Operation.valueOf(resultSet.getString("operation")))
                        .build());

                i++;

                if(i == batchSize) {
                    i = 0;
                    consumer.accept(itemEntities);
                    itemEntities.clear();
                }
            }

            if(!itemEntities.isEmpty())
                consumer.accept(itemEntities);
        } catch (Exception ex) {
            log.error("error", ex);
            throw new RuntimeException("error", ex);
        }
    }

每当这个批处理运行时,容器就会以退出代码 137 重新启动。我已经检查了下面的 jvm 参数

-XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=/var/data/heapdump.hprof

由于容器重启后我没有得到任何堆转储文件所以我假设不是 Micronaut 应用程序导致容器进入 OOM。

容器内存限制为 512m。

我可以尝试调试这个问题的所有方法是什么?

【问题讨论】:

  • 是否有卷挂载到目标转储路径?
  • @tmarwen 是的,它已安装。这不是问题,因为当我为 java 应用程序分配较少的 Xmx 时,我能够生成堆转储。

标签: java sqlite containers out-of-memory micronaut


【解决方案1】:

我认为可以有效调试问题的一种技术,我可以称之为“隔离和剥离”。这背后的想法是将这个问题的所有因素隔离到单独的关注点中,并不断迭代以找出导致问题的最重要因素。这是一个问题识别练习。列出一些候选问题后,您就可以将注意力转移到解决方案的思维方式上。

对于您的特定问题,我可以总结发生的事情(如果我错了,请纠正我)

  • 使用数据库连接准备语句,然后为其分配一些变量,然后执行。
  • 获取结果集。使用结果集,填充项目实体并将它们分批发送给消费者(大约 100 个)。然后重复

从这里我可以提取关注点列表。

    1. sql 查询数据库,预期结果为 50k
    1. 将一个结果集行处理成一个项目实体
    1. 将一个项目实体传递给消费者。

所以隔离这些问题来调试它。同时注释掉或删除代码的其他部分。

对于第 1 项,查看结果集 50k 是否导致 OOM 错误。将查询调整为最大为 10k、20k、30k。或者从1k开始;看看 100 个结果是否有效。稍微改一下查询,看看能不能一点一点往里面加,看看什么时候坏。

对于第 2 项,在 100 的循环中构建项目是一个问题。你能不能把它一直建到 500k。尝试不同的数量。

对于第 3 项,您能否毫无问题地将一件商品处理给消费者。你能不能把刚刚手工创建的模拟项目发送给它,处理一批 100。然后将它提高到一批 1000 或 5000。如果成功,请轮换看看它在什么时候失败。

另一个角度是搞乱内存限制。一旦你有上述工作的一部分,我会在之后这样做,并保持递增直到你看到它坏了。

另一条路线是看看您是否可以使用 Micronaut 存储库和实体来解决相同的问题。在较小的上下文中,例如 100 个实体,然后尝试增加到 50k。从我上面看到的情况来看,我认为这不是 micronaut 问题,但实验将有助于通过证据排除它

【讨论】:

  • 只是一个更正,我们没有将一个 itemEntity 传递给消费者。从结果集中,我们正在创建 batchSize(100) 的 itemEntity 列表并将该列表传递给消费者。消费者处理列表并为每个 itemEntity 调用外部 api,并根据响应在另一个表中插入记录。
  • 还不错。您可以通过减少批量大小并按自己的方式查看它何时实际中断来调整故障排除方法。
猜你喜欢
  • 1970-01-01
  • 2016-05-31
  • 2020-12-09
  • 2011-08-03
  • 2014-07-05
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2020-05-27
相关资源
最近更新 更多