我们有一个管道,它从接收来自PubSub的消息开始,每个消息都有一个文件的名称。这些文件被分解为行级别,解析为JSON对象节点,然后发送到外部解码服务(对某些编码数据进行解码)。对象节点最终转换为Table Rows并写入Big Query。
似乎Dataflow在他们到达解码服务之前没有确认PubSub消息。解码服务很慢,导致一次发送许多消息时出现积压。这意味着与PubSub消息相关联的行可能需要一些时间才能到达解码服务。结果,PubSub没有收到确认并重新发送消息。我第一次尝试解决这个问题是为每个使用withAttributeId()传递给Reader的PubSub消息添加一个属性。但是,在测试时,这只能防止紧密相连的重复。
我的第二次尝试是在PubSub阅读后添加fusion breaker(example)。这只是执行一个不必要的GroupByKey然后取消组合,这个想法是GroupByKey强制Dataflow确认PubSub消息。
上面讨论的融合破坏程序的作用是防止PubSub重新发送消息,但我发现这个GroupByKey输出的元素多于它接收的元素:See image。
为了尝试和诊断这个,我删除了部分管道以获得仍然表现出这种行为的简单管道。
时,行为仍然存在我观察到的行为是:
示例作业ID为2017-10-11_03_50_42-6097948956276262224。我没有对任何其他跑步者跑光束。
Fusion Breaker如下:
@Slf4j
public class FusionBreaker<T> extends PTransform<PCollection<T>, PCollection<T>> {
@Override
public PCollection<T> expand(PCollection<T> input) {
return group(window(input.apply(ParDo.of(new PassthroughLogger<>(PassthroughLogger.Level.Info, "Fusion break in")))))
.apply("Getting iterables after breaking fusion", Values.create())
.apply("Flattening iterables after breaking fusion", Flatten.iterables())
.apply(ParDo.of(new PassthroughLogger<>(PassthroughLogger.Level.Info, "Fusion break out")));
}
private PCollection<T> window(PCollection<T> input) {
return input.apply("Windowing before breaking fusion", Window.<T>into(new GlobalWindows())
.triggering(Repeatedly.forever(AfterPane.elementCountAtLeast(1)))
.discardingFiredPanes());
}
private PCollection<KV<Integer, Iterable<T>>> group(PCollection<T> input) {
return input.apply("Keying with random number", ParDo.of(new RandomKeyFn<>()))
.apply("Grouping by key to break fusion", GroupByKey.create());
}
private static class RandomKeyFn<T> extends DoFn<T, KV<Integer, T>> {
private Random random;
@Setup
public void setup() {
random = new Random();
}
@ProcessElement
public void processElement(ProcessContext context) {
context.output(KV.of(random.nextInt(), context.element()));
}
}
}
PassthroughLoggers只记录通过的元素(我使用这些来确认元素确实重复,而不是计数有问题)。
我怀疑这与windows /触发器有关,但我的理解是,当使用.discardingFiredPanes()时,不应重复元素 - 无论窗口设置如何。我也试过FixedWindows但没有成功。
答案 0 :(得分:1)
首先,Reshuffle
转换相当于您的Fusion Breaker,但还有一些额外的性能改进,应该更适合。
其次,如果重试,计数器和日志记录可能会多次看到一个元素。如Beam Execution Model中所述,如果重试融入的任何内容,则可以重试步骤中的元素。
您是否真的在写入管道输出的内容中发现了重复项?