flink按字段对齐的流合并的实现
最近在用flink重构storm程序,遇到了一些问题,其中比较麻烦的就是storm中的流合并如何在flink中实现。
需求根据每条数据内的时间属性(同一类型的字段),拼装同一时间的多个流数据为一个流数据,尽可能保证只要能合并的数据时间戳对齐。在storm中通过fieldGrouping可以很简单的实现。
.fieldsGrouping("test1", new Fields("time"))
.fieldsGrouping("test2", new Fields("time"));
但在Flink的DataStream中遇到了困难,因为没有找到可以直接实现该方案的api。以下这篇文章记录下我对此的尝试及一些心得。
Unio方法
最开始我设计了合并和分组的方案,即用union合并两个流为一个流,再根据keyby分组,通过reduce组合同组流为一个流。这种方法看起来没问题,每一个进入reduce都能进行正确的组合。但是经过测试发现会产生巨大的数据没法进入reduce,没经过组合直接抛出去了,因此该方案失败。
DataStream1.union(DataStream2).keyBy("dataTime").reduce(new ReduceFunction<TupleEntry>(){
@Override
public TupleEntry reduce(TupleEntry value1, TupleEntry value2) throws Exception {
//字段合并操作
return new TupleEntry(value1.getDataTime(),output);
}
});
Jion方法
后来经过讨论,我尝试了join方法的方法进行流合并,最后通过jion的配置完成了数据的组合。代码如下
DataStream1.join(DataStream2).where(new KeySelector<TupleEntry, Integer> {
@Override
public Integer getKey(TupleEntry value) throws Exception {
return value.getDataTime();
}
}).equalTo(new KeySelector<TupleEntry, Integer> {
@Override
public Integer getKey(TupleEntry value) throws Exception {
return value.getDataTime();
}
})
.window(TumblingEventTimeWindows.of(Time.milliseconds(1000))).apply((new JoinFunction<TupleEntry, TupleEntry, TupleEntry> {
@Override
public TupleEntry join(TupleEntry value1, TupleEntry value2) throws Exception {
//字段合并操作
return new TupleEntry(value1.getDataTime(),output);
}
});
一个需要注意的点是环境变量需要进行一个配置
env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
join其实应该是一个很有用,并且能实现很多功能的方法,但需要where,window,join等较复杂的配置,其中window又是flink中比较复杂的概念,我也产生了两个问腿:
第一是该方案大规模应用/上集群时候是否会产生性能问题?
第二是该方案应该还可以进行其他配置和调优,具体的应用方向是什么?
之后有机会(让我再理解和测试一下),我会再写下这方面的文章。