Spring Batch:用于高容量和低延迟的哪种ItemReader实现

19

使用场景:从数据库中读取1000万行数据[10列],并将其写入文件(csv格式)。

  1. JdbcCursorItemReaderJdbcPagingItemReader之间,应该选择哪种ItemReader实现?原因是什么?

  2. 在上述使用场景中,哪个实现性能更好(更快)?

  3. 如果采用单进程与多进程的方法,选择是否不同?

  4. 如果采用TaskExecutor进行多线程处理,哪一种方法更好、更简单?


1
将CSV文件分割成多个部分并添加额外步骤以将这些部分合并为单个CSV文件? - Luca Basso Ricci
@bellabax 请考虑采用单进程方法[暂时]。更新问题以询问单进程/多进程是否重要。 - ram
2个回答

12
要处理这种类型的数据,如果可能的话,您可能希望并行化处理它(唯一阻止并行化的因素是输出文件需要保留输入顺序)。假设您要并行化处理,那么对于这种用例,您将有两个主要选项(根据您提供的信息):
1. 多线程步骤-这将每个线程处理一个块,直到完成。这样可以轻松地进行并行化(只需在步骤定义中添加TaskExecutor即可)。但是,由于需要关闭您提到的任何ItemReader上的状态持久性,因此您会失去开箱即用的可重启性(可以通过标记数据库中已处理过的记录等方法解决)。
2. 分区-这将您的输入数据分成分区,并由并行处理的步骤实例(主/从配置)处理。分区可以通过线程本地执行(通过TaskExecutor),也可以通过远程分区执行。无论哪种情况,都可以通过并行化获得可重启性(每个步骤处理自己的数据,因此不存在从分区到分区的状态冲突)。
我曾就使用Spring Batch在并行处理数据方面发表过演讲。具体而言,我展示的例子是一个远程分区作业。您可以在此处查看:https://www.youtube.com/watch?v=CYTj5YT7CZU
针对您的具体问题:
  1. 在JdbcCursorItemReader和JdbcPagingItemReader之间,哪种ItemReader实现更值得推荐?原因是什么? - 这两个选项都可以进行调整以满足许多性能需求。这真的取决于您使用的数据库、可用的驱动程序选项以及您可以支持的处理模型。另一个考虑因素是,您是否需要可重启性?
  2. 在上述用例中,哪个执行效率更高(快)? - 再次取决于您选择的处理模型。
  3. 如果采用单进程与多进程方法,选择会有所不同吗? - 这涉及到如何管理作业,而不是Spring Batch可以处理什么。问题是,您想将分区管理外部化(将数据描述作为参数传递给作业),还是要让作业管理它(通过分区)。
  4. 在使用TaskExecutor的多线程方法中,哪一个更好且更简单? - 我不会否认远程分区添加了本地分区和多线程步骤没有的复杂性。
我会从基本的步骤定义开始。然后尝试多线程步骤。如果这不能满足您的需求,那么就转向本地分区,最后是远程分区(如果需要)。请记住,Spring Batch旨在使该进程尽可能轻松。您可以通过仅进行配置更新即可从常规步骤转换为多线程步骤。要进行分区,您需要添加一个新的类(Partitioner实现)和一些配置更新。
最后一点。大部分讨论都是关于并行处理数据。Spring Batch的FlatFileItemWriter不是线程安全的。如果速度是您的首要考虑因素,则最好同时写入多个文件,然后在之后进行聚合。

你之前提到了在分区之前的“多线程步骤”。然而,在多线程步骤中使用JdbcCursorItemReader时,可能会出现ResultSetExhaustedException异常。如何解决这个问题? - ram
JdbcCursorItemReader不被认为是线程安全的。在多线程步骤中使用JdbcPagingItemReader。您可以在此处阅读有关详细信息:https://jira.springsource.org/browse/BATCH-2050?focusedCommentId=96509&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-96509 - Michael Minella

9

为了做出选择,您应该对此进行分析。在普通的JDBC中,我会从以下方面开始:

  • 使用 ResultSet.TYPE_FORWARD_ONLYResultSet.CONCUR_READ_ONLY 准备语句。除非使用这两个选项,否则几个 JDBC 驱动程序会在客户端模拟游标,对于大型结果集,您不希望这样做,因为它可能导致 OutOfMemoryError,因为 JDBC 驱动程序正在内存中缓冲整个数据集。通过使用这些选项,您增加了获得服务器端游标并逐位“流式传输”结果的机会,这是您对于大型结果集所需的。请注意,某些 JDBC 驱动程序始终在客户端模拟游标,因此此提示可能对您特定的 DBMS 无用。
  • 设置合理的 提取大小 以最小化网络往返的影响。50-100 通常是分析的良好起点。由于提取大小是提示,因此这对于您特定的 DBMS 也可能是无用的。

JdbcCursorItemReader似乎涵盖了这两个方面,但正如之前所说,它们不能保证在所有DBMS中都提供最佳性能,因此我建议从那里开始,如果性能不足,则尝试JdbcPagingItemReader

我认为,除非您有非常严格的性能要求,否则使用JdbcCursorItemReader进行简单处理不会很慢。如果您确实需要并行处理,使用JdbcPagingItemReader可能更容易,但这两者的接口非常相似,因此我不会指望太多。

无论如何,进行性能分析


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接