如何使用来自JDBC连接器的高吞吐量JAVA I / O流来避免内存溢出?

时间:2019-07-09 14:36:24

标签: java stream spring-data-jpa garbage-collection

考虑从(w.r.t内存)无限源中提取有限数量数据的任务,例如我需要在一个有限但可能很大的时间窗口内,从一个由数十亿个条目组成的庞大表中获取counts,并用timestampforeign_key标记。但是,为了以后使用,我只需要最大gridSize值。

注意: 支持数据库是MariaDb,我们使用spring数据jpa连接到数据库。

一种基于流的方法是:

int stepSize = (int) (numberOfCountsInWindow / gridSize) + 1;

StreamUtils
     .zipWithIndex(countStream)
     .filter(countIndexed -> countIndexed.getIndex() % stepSize == 0)
        ...
        <intermediate steps>
        ...
     .collect(Collectors.toList())

我尝试了很多其他方法,例如:

  • 自定义Collector,它使用AtromicLong来确定下一个值是添加到最终列表中还是被忽略,
  • Flux.defere(()->),以使用Flux背压管理
  • Java 11
  • 大量MySQL选项(例如“ useCursorFetch = true”)与有限的预取大小为@QueryHint()组合
  • ...

但是,我尝试过的所有操作都导致GC overhead limit exceeded(堆大小限制为2048,这是我们应用程序的默认值)。

原因是,cpu完全忙于垃圾回收,而内存消耗一直在填满,直到最终应用程序崩溃为止。

我真正期望(或至少希望)的是流“实现”过滤并仅继续实际计算(最多使用100%cpu)和垃圾收集器轻松删除未使用的对象,因为它们无论如何都会被过滤掉,甚至不需要解析(希望流的懒惰在这里有所帮助)。但是,这似乎不符合我的期望。

非常欢迎提出意见或建议,因为我想(至少)理解(最好解决),而不是仅仅接受这种情况。

编辑:也欢迎使用MariaDB的替代产品(也许是Cassandra?)。

0 个答案:

没有答案