用于大型更新/插入的DataNucleus内存/缓存处理

时间:2013-08-02 03:47:28

标签: memory datanucleus heap-dump

我们在Spring上下文中运行应用程序,使用DataNucleus作为我们的ORM映射,mysql作为我们的数据库。

我们的应用程序每天都会将一些数据输入到我们的数据库中。数据馈送的大小转换为大约100万行插入/更新。导入的性能开始非常好但随后它会降低超时(随着执行的查询数量的增加),并且在某些时候应用程序冻结或停止响应。我们将不得不等待整个工作在申请回复之前完成。

这种行为看起来非常像我们的内存泄漏,我们一直在努力查看我们的代码以捕获任何潜在的问题,但问题并没有消失。我们从堆转储中发现的一个有趣的事情是org.datanucleus.ExecutionContextThreadedImpl(或HashSet / HashMap)在导入期间保留了90%的内存(5GB)。 (我已经获得了下面转储的屏幕截图)。我在互联网上的研究表明这个参考是Level1 Cache(不确定我是否正确)。我的问题是在大量导入期间,如何限制/控制level1缓存的大小。可能要求DN在导入期间不缓存?

如果那不是L1缓存,那么我内存问题的可能原因是什么?

我们的代码为每个插入使用一个事务来防止锁定数据库中的大块数据。它每2000插入一次调用flush方法

作为一个临时修复,我们将导入过程移动到一夜之间没有人使用我们的应用程序。显然,这不可能永远持续下去。请有人至少指出我们正确的方向,以便我们可以做更多的研究,并希望我们能找到一个修复。

如果有人知道解码堆转储

会很好

我们所有人都非常感谢您的帮助。非常感谢!

https://s3-ap-southeast-1.amazonaws.com/public-external/datanucleus_heap_dump.png

https://s3-ap-southeast-1.amazonaws.com/public-external/datanucleus_dump2.png

以下代码 - 此方法的调用者没有事务。此方法将每次调用处理一个导入对象,并且我们需要每天处理大约100K这些对象

@Override
@PreAuthorize("(hasUserRole('ROLE_ADMIN')")
@Transactional(propagation = Propagation.REQUIRED)
public void processImport(ImportInvestorAccountUpdate account, String advisorCompanyKey) {

    ImportInvestorAccountDescriptor invAccDesc = account
            .getInvestorAccount();

    InvestorAccount invAcc = getInvestorAccountByImportDescriptor(
            invAccDesc, advisorCompanyKey);

    try {

        ParseReportingData parseReportingData = ctx
                .getBean(ParseReportingData.class);

        String baseCCY = invAcc.getBaseCurrency();
        Date valueDate = account.getValueDate();
        ArrayList<InvestorAccountInformationILAS> infoList = parseReportingData
                .getInvestorAccountInformationILAS(null, invAcc, valueDate,
                        baseCCY);

        InvestorAccountInformationILAS info = infoList.get(0);

        PositionSnapshot snapshot = new PositionSnapshot();
        ArrayList<Position> posList = new ArrayList<Position>();
        Double totalValueInBase = 0.0;
        double totalQty = 0.0;



        for (ImportPosition importPos : account.getPositions()) {
            Asset asset = getAssetByImportDescriptor(importPos
                    .getTicker());
            PositionInsurance pos = new PositionInsurance();
            pos.setAsset(asset);
            pos.setQuantity(importPos.getUnits());
            pos.setQuantityType(Position.QUANTITY_TYPE_UNITS);
            posList.add(pos);
        }

        snapshot.setPositions(posList);
        info.setHoldings(snapshot);

        log.info("persisting a new investorAccountInformation(source:"
                + invAcc.getReportSource() + ") on " + valueDate
                + " of InvestorAccount(key:" + invAcc.getKey() + ")");
        persistenceService.updateManagementEntity(invAcc);



    } catch (Exception e) {
        throw new DataImportException(invAcc == null ? null : invAcc.getKey(), advisorCompanyKey,
                e.getMessage());
    }

}

1 个答案:

答案 0 :(得分:0)

你对整个工作使用相同的下午吗?

如果是这样,您可能希望偶尔尝试关闭并创建新的。

如果没有,这可能是L2缓存。你对datanucleus.cache.level2.type有什么设置?它认为默认情况下它是一个弱映射。您可能希望尝试不进行测试。