我尝试为Google Cloud Dataflow实施自定义无限制来源,以便从Amazon Kinesis队列中读取数据。为了正确实现检查点,我想了解该机制是如何正常工作的。
我试图通过阅读DataFlow的文档来了解检查点,但是缺少一些关键的东西,所以我浏览了一篇MillWheel论文。首先让我解释一下我是如何理解本文所提出的概念的。在数据流API方面,我将重点关注源代码与其消费者之间在强大的生产设置中的交互:
createReader()
,并将null值作为CheckpointMark传递start()
advance()
在读者上被称为X次getCheckpointMark()
。finalizeCheckpoint()
现在,请让我谈谈Kinesis队列如何运作,因为它与Pub / Sub存在显着差异(因为我了解Pub / Sub的工作原理,我自己也没有使用它) )。
我看到Pub / Sub pull模型严重依赖于ACK,即客户端接收的消息被确认,然后是内部检查点"在Pub / Sub中向前移动 - >这意味着即将到来的拉取请求将在前一次ACK之后接收连续记录。
Kinesis pull界面(根本没有推送)与你与文件交互的方式更相似。您可以在流中的任何位置开始读取(特殊值TRIM_HORIZON是流中最旧的记录,LATEST是流中的最新记录)然后使用迭代器按记录向前移动(迭代器存储在服务器端并具有5分钟到期时间,如果未使用)。没有服务器的确认 - 客户有责任跟踪流中的位置,并且您可以随时重新读取旧记录(当然,除非它们已过期)。
getCurrentRecordId
返回的值吗?我问这个问题,因为我考虑过使用流中的位置,因为它对特定的流是唯一的。但是如果我以后通过展平它们加入一些kinesis来源会发生什么呢?>这将导致不同记录可能共享相同ID的情况。我应该使用(流名称,位置)元组作为id(在这种情况下是唯一的)。干杯, Przemek
答案 0 :(得分:3)
我们很高兴看到您将数据流与Kinesis一起使用。我们希望通过GitHub project向我们的contrib connector for Kinesis提取拉取请求。我们也很乐意在您开发时通过GitHub审核您的代码并在那里给您反馈。
检查点应该如何?给定检查点的读者是否只读取与其相关的部分数据,或者是否希望从检查点读取所有数据?换句话说,我的检查点应该是:" x和y之间的数据"或" x"?
之后的所有数据
检查点标记应代表“此读者已生成并最终确定的数据”。例如,如果读者负责特定分片,则检查点标记可能包含分片标识符和该分片中已成功读取的最后序列号Y,表示“已生成所有数据,包括Y”。
我知道第一个读取器作为检查点标记变为空,并且完全没问题 - 这意味着我应该从应用程序开发人员定义的点开始阅读。但DataFlow是否可以像这样创建其他读取器(例如,我想象读取器jvm死亡的情况,然后DataFlow创建新的读取器传递null作为检查点的新读者)?在这种情况下,我不知道我的起始位置是什么,因为我可能已经使用以前的读者阅读了一些数据,现在进度的标记已经丢失。
即使在JVM失败的情况下,也会保留最终检查点。换句话说,当JVM死亡时,读者将使用最终确定的最后一个检查点构建。您不应该看到使用空检查点创建的读者,除非它们打算从源的开头读取,或者在JVM在第一次成功调用finalizeCheckpoint()
之前死亡的情况下读取。您可以使用新阅读器上的检查点标记为从要读取的下一条记录开始的相同分片构造新的迭代器,并且可以继续而不会丢失数据。
什么ID用于消费者方面的记录重复数据删除?它是由getCurrentRecordId返回的值吗?我问这个问题,因为我考虑过使用流中的位置,因为它对特定的流是唯一的。但是如果我以后通过展平它们加入一些kinesis来源会发生什么呢?>这将导致不同记录可能共享相同ID的情况。我应该使用(流名称,位置)元组作为id(在这种情况下是唯一的)。
在Dataflow中,每个UnboundedSource(实现getCurrentRecordId
并覆盖requiresDeduping
以返回true
)都会自行删除。因此,记录ID仅对同一源实例是唯一的。来自两个不同来源的记录可以使用相同的记录ID,并且在展平期间不会将它们视为“重复”。因此,如果Amazon Kinesis保证所有记录都具有全局唯一的ID(跨流中的所有分片)和持久性(例如,通过重新分片操作),那么这些ID应该适合用作记录ID。
请注意,getCurrentRecordId
是UnboundedReader
的可选方法 - 如果您的检查点方案唯一标识每条记录,则无需实现它。 Kinesis允许您按序列号顺序读取记录,看起来序列号是全局唯一的。因此,您可以将每个分片分配给generateInitialSplits
中的其他工作人员,并且每个工作人员可能不会生成重复数据 - 在这种情况下,您可能根本不需要担心记录ID。
这个答案的大部分都假设了一个简单的例子,你的Kinesis流不会改变它们的分片。另一方面,如果流上的分片发生变化,那么您的解决方案将变得更加复杂。例如,每个工人可能负责超过1个碎片,因此检查点标记将是碎片地图 - >序号而不是序号。拆分和合并的分片可以在不同的数据流工作者之间移动以平衡负载,并且可能很难保证两个不同的工作人员不会读取两次Kinesis记录。在这种情况下,使用带有您描述的语义的Kinesis记录ID就足够了。