Flink 聚合对账

Flink Aggregation Reconciliation

DynamoDB 中的事务 table

Transactions {transaction_id, customer_id, statment_id, transaction_date, transaction_amount}

DynamoDB 中的语句 table

Statements {statement_id, customer_id, start_time, end_time, statement_amount}

任何一天都有数百万笔交易发生。我正在考虑使用 Flink 使用 DynamoDB 流将交易金额汇总为报表金额。

在任何给定时间点,我都需要知道是否汇总了属于某个报表的所有交易金额。也就是说,显示对帐单金额是否过时。本质上,我在谈论和解。我如何在 Flink 中实现它?

很容易使用 KeyedProcessFunction 之类的东西来持续更新一些 Flink 状态,这些状态在摄取新事务时为每个 statement_id 聚合 statement_amount。但据我了解,问题是如何知道该聚合何时完成,或者换句话说,Flink 何时处理了给定 statement_id.

的所有事务

流处理应用程序总是面临这个问题。与可以简单地处理所有数据然后产生结果的批处理不同,使用流处理我们一次处理一条记录,不知道将来会发生什么, 或者有多少延迟。

这导致我们在延迟完整性之间进行权衡。一般来说,人们总是可以等待更长的时间,看看有什么额外的数据到达,从而增加一个人根据(更)完整的信息产生结果的机会。水印是这种权衡的技术表现。任何使用事件时间的流应用程序都必须生成水印,每个水印用时间戳标记流中的一个点,并声明流在该点可能完成时间戳。

对于某些应用程序,快速生成可能正确的结果很好,事实上,这可能比等待更长的时间来生成更可能正确的结果要好。但在其他应用程序中,有必要完全准确(无论这意味着什么,准确)。

具体应该做什么不是技术问题,而是业务流程问题。最终,这取决于对帐报表对您的业务意味着什么。也许您应该致力于重现当前任何进程的语义。

话虽如此,Flink 提供了一组工具,您可以结合使用以多种方式解决此用例,具体取决于您希望它如何工作的细节。以下是各个部分如何组合在一起:

每条语句都有一个end_time。当事务流的水印达到 end_time 时,这是人们可能认为该语句的事务聚合已完成的第一个时刻。

这个水印(通常)是在指定交易流可以乱序的数量的基础上完成的。但是你要预料到,无论你多么悲观,一些异常交易都会违反这个假设,相对于水印

为了解决这个问题,您可以增加水印延迟以尝试涵盖所有可能的延迟(有人可能会争辩说,一般来说,这是不可能的),或者决定在某个时候您必须继续并生成一个声明声称已协调,但实际上可能需要在将来进行更新或修改。这个任意迟到的问题是否是一个真正的问题(就像在银行业一样,一些国际交易可能会经历很长时间的延迟),或者仅仅是理论上的,取决于您的实际用例。

能够容纳延迟事务将需要您 (1) 将语句数据保留在 Flink 的托管状态中,以便添加延迟事务,然后可以将其用于更新语句,或者(2) 以特殊方式处理延迟事件,通过从数据库中读取先前生成的结果,然后更新数据库中的记录(这需要以事务方式完成)。方法 #2 可以在一个单独的作业中实现,该作业消耗第一个作业产生的延迟事务流。

您可以通过在声明中包含一个时间戳来定义解决此问题的方法,该时间戳指定该声明恰好包括截至该时间点已处理的那些交易。