Apache flink 基于优先级或循环方式使用两个flink数据流

Apache flink 基于优先级或循环方式使用两个flink数据流,apache-flink,flink-streaming,Apache Flink,Flink Streaming,我有两个flinkdataStream。例如:dataStream1和dataStream2。我想将两个流合并成一个流,这样我就可以使用相同的处理函数来处理它们,因为两个dataStream的dag是相同的 到目前为止,我需要两个流的消息消费具有相同的优先级。 dataStream2的生产者每分钟产生10条消息,而dataStream1的生产者每秒产生1000条消息。另外,两个数据流的数据类型都相同。DataSteam2是一个更高优先级的队列,应该尽快使用。dataStream1和dataStr

我有两个flink
dataStream
。例如:
dataStream1
dataStream2
。我想将两个流合并成一个流,这样我就可以使用相同的处理函数来处理它们,因为两个
dataStream
的dag是相同的

到目前为止,我需要两个流的消息消费具有相同的优先级。 dataStream2的生产者每分钟产生10条消息,而dataStream1的生产者每秒产生1000条消息。另外,两个数据流的数据类型都相同。DataSteam2是一个更高优先级的队列,应该尽快使用。dataStream1和dataStream2的消息之间没有关系


dataStream1.union(dataStream2)
是否会生成一个包含两个流元素的流?

连接两个流可能是解决此问题的最简单解决方案,但并非最有效的解决方案,具体取决于数据源的确切规格。在这个解决方案中,您可以使用
协处理函数
,它将为每个连接的流调用单独的方法


在这个解决方案中,您可以简单地缓冲一个流的元素,直到可以生成它们为止(例如,以循环方式)。但是请记住,如果源生成事件的频率之间存在很大差异,那么这可能会非常低效。

听起来这两个
数据流有不同类型的元素,尽管您没有明确指定。如果是这种情况,则在每个流上通过
MapFunction
创建一个
or
,然后在两个流上创建
union()
。您不会得到两者的精确混合,因为Flink将交替使用每个流的网络缓冲区


如果您真的想要很好地混合流,那么(正如其他人所指出的),您需要通过状态来缓冲传入元素,并且还需要应用一些启发式方法来避免由于任何原因(例如,不同的网络延迟,或者两个源之间更可能存在不同的性能)而过度缓冲两个数据流之间的数据速率非常不同。

您可能需要使用实现
InputSelectable
接口的自定义运算符,以减少所需的缓冲量。我在下面提供了一个示例,该示例实现了无缓冲的交错,但请务必阅读中的警告,其中解释了这一点

。。。操作员可能会收到一些当前不想处理的数据

换句话说,这个简单的例子不能被依赖于真正的工作

public class Alternate {
    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        DataStream<Long> positive = env.generateSequence(1L, 100L);
        DataStream<Long> negative = env.generateSequence(-100L, -1L);

        AlternatingTwoInputStreamOperator op = new AlternatingTwoInputStreamOperator();

        positive
            .connect(negative)
            .transform("Hack that needs buffering", Types.LONG, op)
            .print();

        env.execute();
    }
}

class AlternatingTwoInputStreamOperator extends AbstractStreamOperator<Long>
        implements TwoInputStreamOperator<Long, Long, Long>, InputSelectable {

    private InputSelection nextSelection = InputSelection.FIRST;

    @Override
    public void processElement1(StreamRecord<Long> element) throws Exception {
        output.collect(element);
        nextSelection = InputSelection.SECOND;
    }

    @Override
    public void processElement2(StreamRecord<Long> element) throws Exception {
        output.collect(element);
        nextSelection = InputSelection.FIRST;
    }

    @Override
    public InputSelection nextSelection() {
        return this.nextSelection;
    }
}
公共类备用{
公共静态void main(字符串[]args)引发异常{
StreamExecutionEnvironment env=StreamExecutionEnvironment.getExecutionEnvironment();
环境(一);
数据流阳性=环境生成序列(1L,100L);
数据流负值=环境生成序列(-100L,-1L);
AlternatingWOInputStreamOperator op=新的AlternatingWOInputStreamOperator();
积极的
.连接(负片)
.transform(“需要缓冲的黑客”,Types.LONG,op)
.print();
execute();
}
}
类AlternatingWoInputStreamOperator扩展了AbstractStreamOperator
实现两个InputStreamOperator,InputSelectable{
私有InputSelection nextSelection=InputSelection.FIRST;
@凌驾
public void processElement1(StreamRecord元素)引发异常{
输出。收集(元素);
nextSelection=InputSelection.SECOND;
}
@凌驾
public void processElement2(StreamRecord元素)引发异常{
输出。收集(元素);
nextSelection=InputSelection.FIRST;
}
@凌驾
公共输入选择下一个选择(){
返回此.nextSelection;
}
}

另外请注意,Flink 1.9.0中添加了
InputSelectable

欢迎!到底是什么问题?数据流来自哪里?直接来自源组件?数据流是脉冲星主题的源组件。@Christophe有。union()将产生数据流,这将是两个数据流的循环。@NischalKumar
union()
没有引入任何规则IIRC。因此,如果您的一个源比另一个源生成元素的速度快,那么它将无法调节流。当每个连接的流都需要单独的业务逻辑时,协处理函数是有意义的。在我的例子中,业务逻辑是完全相同的。为什么不让
协处理函数中的每个方法调用一个公共方法来处理记录呢?你在这里的评论让我觉得你的问题比上面所描述的更重要。当数据类型不同时,使用协处理函数是有意义的。在我的用例中,dataStram1的数据类型与dataStream2相同,但dataStream1生产者每秒产生10^3条消息,而dataStream2每分钟产生10条消息。我想要一个循环策略,这样dataSteam2也会与dataSteam1消息一起使用。由于dataStream2的速率非常低,它应该在到达时立即得到处理。@Niscalkumar不完全是,因为协处理函数实际上是一个函数,由于存在
收集器
,它将允许您不为给定流发出输出,而只是缓冲它并等待来自其他流的输入。两个数据流的数据类型相同