Flink(四十七)—— 如何使用 Side Output 来分流?

97 篇文章 91 订阅

前言

之前 讲过 Flink 使用连续的 Split 会有问题,当时提供了几种解决方法,有一种方法就是使用 Side Output 来进行,当时留了个余念,那么就在这篇文章详细的讲一波,教大家如何使用 Side Output 来分流。

Side Output

通常我们在处理数据的时候,有时候想对不同情况的数据进行不同的处理,那么就需要把数据流进行分流。比如我们在那篇文章里面的例子:需要将从 Kafka 过来的告警和恢复数据进行分类拆分,然后在对每种数据再分为告警数据和恢复数据。

如果是使用 filter 来进行拆分,也能满足我们的需求,但每次筛选过滤都要保留整个流,然后通过遍历整个流来获取相应的数据,显然很浪费性能。假如能够在一个流里面就进行多次输出就好了,恰好 Flink 的 Side Output 则提供了这样的功能。

如何使用?

要使用 Side Output 的话,你首先需要做的是定义一个 OutputTag 来标识 Side Output,代表这个 Tag 是要收集哪种类型的数据,如果是要收集多种不一样类型的数据,那么你就需要定义多种 OutputTag。例如:如果我要将告警/恢复的数据分为机器、容器、中间件等的数据,那么我们起码就得定义三个 OutputTag,如下:

private static final OutputTag<AlertEvent> middleware = new OutputTag<AlertEvent>("MIDDLEWARE") {
};
private static final OutputTag<AlertEvent> machine = new OutputTag<AlertEvent>("MACHINE") {
};
private static final OutputTag<AlertEvent> docker = new OutputTag<AlertEvent>("DOCKER") {
};

然后呢,你可以使用下面几种函数来处理数据,在处理数据的过程中,进行判断将不同种类型的数据存到不同的 OutputTag 中去。

  • ProcessFunction
  • KeyedProcessFunction
  • CoProcessFunction
  • ProcessWindowFunction
  • ProcessAllWindowFunction

比如:

//dataStream 是总的数据流
SingleOutputStreamOperator<AlertEvent, AlertEvent> outputStream = dataStream.process(new ProcessFunction<AlertEvent, AlertEvent>() {
    @Override
    public void processElement(AlertEvent value, Context ctx, Collector<AlertEvent> out) throws Exception {
        if ("MACHINE".equals(value.type)) {
            ctx.output(machine, value);
        } else if ("DOCKER".equals(value.type)) {
            ctx.output(docker, value);
        } else if ("MIDDLEWARE".equals(value.type)) {
            ctx.output(middleware, value);
        } else {
            //其他的业务逻辑
            out.collect(value);
        }
    }
})

好了,既然上面我们已经将不同类型的数据进行放到不同的 OutputTag 里面了,那么我们该如何去获取呢?你可以使用 getSideOutput 方法来获取不同 OutputTag 的数据,比如: 

//机器相关的告警&恢复数据
outputStream.getSideOutput(machine).print();

//容器相关的告警&恢复数据
outputStream.getSideOutput(docker).print();

//中间件相关的告警&恢复数据
outputStream.getSideOutput(middleware).print();

这样你就可以获取到 Side Output 数据了。

另外你还可以看下我在 Github 放的一个完整 demo 代码: https://github.com/zhisheng17/flink-learning/blob/master/flink-learning-examples/src/main/java/com/zhisheng/examples/streaming/sideoutput/Main.java

在Apache Flink的DataStream API中,`BroadcastProcessFunction`是一个特殊的处理函数类型,它允许您将数据广播到所有并行实例上的一次性操作。这种功能通常用于需要全局共享状态或对输入数据进行预处理的情况,比如在每个元素上执行一些基于全局数据的操作。 要在Java中使用`BroadcastProcessFunction`实现边输出(side output),你可以按照以下步骤操作: 1. **创建BroadcastProcessFunction**: 首先,你需要定义一个继承自`BroadcastProcessFunction`的类,并覆盖`processElement()`方法。在这个方法里,你可以处理输入元素并利用`broadcast()`方法发送side output。 ```java public class MyBroadcastFunction extends BroadcastProcessFunction<YourInputType, YourOutputType> { private transient BroadcastValue<GlobalData> globalData; @Override public void open(Configuration parameters) throws Exception { super.open(parameters); globalData = getRuntimeContext().getBroadcastVariable("globalData"); } @Override public void processElement(YourInputType value, Context ctx, Collector<YourOutputType> out) throws Exception { // 使用globalData进行预处理或计算 GlobalData processedData = doPreProcessing(value, globalData.value()); // 发送side output ctx.output(processedData); } } ``` 2. **设置Broadcast变量**: 在作业启动前,你需要通过`addBroadcastVariable()`方法提供全局数据,例如: ```java StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 全局数据 GlobalData.globalData = ...; env.execute(() -> { DataStream<YourInputType> input = ...; // 输入流 input.process(new MyBroadcastFunction()) .addSink(Sink...); // 将side output的结果存入某个sink }); ``` 3. **配置并行度**: 如果你想让全局数据只在每个并行任务实例中复制一份,记得设置合适的并行度。如果并行度很高,可能会消耗大量的内存。 ```java env.setParallelism(1); // 或者其他适合的并行度 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值