我有一个自定义接收器,它会将最终结果从管道发布到存储库。
我从BigQuery和GCS获取此管道的输入。
所有工作人员都会调用存在于接收器中的自定义编写器。 Custom Writer将收集要打印的对象并将其作为WriteResult的一部分返回。最后我将这些记录合并到CustomWriteOperation.finalize()中并将其推送到我的存储库中。
这适用于较小的文件。但是,如果结果大于5 MB,我的存储库将不会接受。此外,它不会接受每小时不超过20次写入。
如果我通过worker推送结果,那么将违反每天的写入限制。如果我在CustomWriteOperation.finalize()中写它,那么它可能违反大小限制,即5MB。
当前的方法是在CustomWriteOperation.finalize()中编写块。由于这在许多工人中没有执行,可能会导致我的工作延误。如何在finalize()中使用worker,如何指定在特定作业(即写入作业)的管道中使用的worker数?
或者有更好的方法吗?
答案 0 :(得分:1)
接收器API没有明确允许调整束大小。
一种解决方法可能是使用ParDo将记录分组到捆绑包中。例如,您可以使用DoFn为每个记录随机分配1,...,N之间的密钥。然后,您可以使用GroupByKey将记录分组为KV< Integer,Iterable< Records>>。这应该产生大约相同大小的N组。
因此,调用Sink.Writer.write可以立即写入具有相同键的所有记录,并且由于并行调用write,因此将并行写入bundle。
但是,由于给定的KV对可以多次处理或同时处理多个工作程序,因此您需要实现一些机制来创建锁,以便您只尝试编写一组记录一次。
您还需要处理失败和重试。
答案 1 :(得分:0)
所以,如果我理解正确,你有一个存储库
这意味着不可能在1小时内写出超过X * Y的数据,所以我想,如果你想写更多,你会希望你的管道等待超过1小时。
Dataflow目前不提供强制执行这些限制的内置支持,但是您似乎应该能够简单地使用随机指数退避进行重试以绕过第一个限制(here's a good discussion) ,它只是为了确保个人写入不是太大。
可以在自定义接收器的Writer类中完成对个别写入的限制。您可以维护一个记录缓冲区,并将write()添加到缓冲区并通过发出API调用(如所提到的那样指数退避)来刷新它,如果它刚好低于允许的写入大小,则再刷新一次在close()。
通过这种方式,您可以编写尽可能大但不大的捆绑包,如果添加重试逻辑,也会受到限制。
总的来说,这似乎很适合Sink API。
答案 2 :(得分:0)
我正在与Sam合作,以下是我们的目标系统实施的实际限制:每个api呼叫 100 GB,每天最多25个api呼叫。
鉴于这些限制,使用退避逻辑的重试方法可能会导致上传需要很多天才能完成,因为我们无法控制工作人员数量。
另一种方法是利用FileBasedSink并行编写多个文件。一旦写完所有这些文件,finalize(或copyToOutputFiles)就可以组合文件,直到总大小达到100 GB并推送到目标系统。这样我们就可以利用编写器线程的并行化,并从目标系统中获得限制。
对此或其他想法的想法?