flink广播流

        广播流是一种在流处理中常用的概念,用于将静态数据或配置信息广播给所有流处理任务,以便这些任务可以共享或使用这些数据。让我们通过一个生动的示例来详细解释广播流,并编写一段Java代码来演示其用处。

示例场景

        假设你正在开发一个实时电商平台,需要在流处理中实时比较商品的价格,并且商品价格可能随时发生变化。同时,你希望能够在不停止流处理作业的情况下动态更新商品价格,而不必重新部署作业。这是广播流可以发挥作用的典型场景。

        个人认为当一个数据流需要另一个不停变化实时数据参与计算处理时,可以将不停变化的实时数据作为广播流,将两者connect从而满足,在不停止原有数据流处理任务的情况能实时满足变化的计算需求。

首先我们定义一个简单类,华为meta60的价格:

package source;

public class price {
    //设置商品名称
    String a = "华为meta60";
    //初始化商品价格
    int b = 0;
    public price(int b) {
        this.b = b;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getA() {
        return a;
    }

    public int getB() {
        return b;
    }
}

 再定义一个用于实时产生华为指导meta60随机价格的类:

package source;

import org.apache.flink.streaming.api.functions.source.SourceFunction;
import java.util.Random;

//用于广播流
public class YaoBroadcastSource implements SourceFunction<price> {

    Random random= new Random();
    boolean a=true;
    @Override
    public void run(SourceContext ctx) throws Exception {
        while (a){
            //生成随机价格
            int l = random.nextInt();
            price price1 = new price(l);
            ctx.collect(price1);
            //定时休眠一段时间,模拟价格的变化过程
            Thread.sleep(10000);
        }
    }

    @Override
    public void cancel() {
        a=false;
    }
}

 最后定义一个实时生成当前华为meta60的价格:

package source;

import org.apache.flink.streaming.api.functions.source.SourceFunction;
import java.util.Random;

public class YaoSource implements SourceFunction<Integer> {
   Random random= new Random();
    boolean a=true;
    @Override
    public void run(SourceContext ctx) throws Exception {
        while (a){
            int l = random.nextInt();
            ctx.collect(l);
            Thread.sleep(3000);
        }
    }

    @Override
    public void cancel() {
        a=false;
    }
}

 现在利用广播流,当华为meta60指导价小于华为meta60当前实时价格时,则输出到下流报警:

package Sideoutput;

import org.apache.flink.api.common.restartstrategy.RestartStrategies;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.streaming.api.datastream.BroadcastStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
import org.apache.flink.util.Collector;
import source.YaoBroadcastSource;
import source.YaoSource;
import source.price;

import java.util.concurrent.TimeUnit;

public class YaoBroadcastProcessFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
        //设置重试次数
//        executionEnvironment.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, Time.of(10, TimeUnit.SECONDS)));
        //定义广播流
        DataStreamSource<price> integerDataStreamSource1 = executionEnvironment.addSource(new YaoBroadcastSource());
//        integerDataStreamSource1.map(i -> {System.out.println(i.getA());return i;});
        // 创建MapStateDescriptor来描述广播流的状态,“productPrices”是状态名称,String.class是键的类型,Integer.class是值的类型
        MapStateDescriptor<String, Integer> productPriceDescriptor = new MapStateDescriptor<>("productPrices", String.class, Integer.class);
        //创建广播流
        BroadcastStream<price> broadcast = integerDataStreamSource1.broadcast(productPriceDescriptor);

        //普通数据流
        DataStreamSource<Integer> integerDataStreamSource = executionEnvironment.addSource(new YaoSource());
        //将普通数据流和广播流进行关联,从而使广播流能够影响普通数据流
        integerDataStreamSource.connect(broadcast)
                //第一个Integer代表主流(Main Input)的数据类型,第二个price代表广播流(Broadcast Input)的数据类型,第三个Integer代表函数的输出数据类型
                .process(new BroadcastProcessFunction<Integer, price, Integer>() {
                    @Override
                    //processElement 方法用于处理主流(Main Input)中的每个元素(事件)。主流通常包含实时数据,你可以在这个方法中对主流中的事件进行处理、转换或过滤,并生成输出。
                    public void processElement(Integer value, BroadcastProcessFunction<Integer, price, Integer>.ReadOnlyContext ctx, Collector<Integer> out) throws Exception {
                        //获取广播流中的属性状态
                        ReadOnlyBroadcastState<String, Integer> broadcastState = ctx.getBroadcastState(productPriceDescriptor);
                        //获取广播流中的属性状态的值
                            Integer integer = broadcastState.get("华为meta60");
                            if (integer == null) {
                                System.out.println("integer为空指针!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                            } else {
                                System.out.println("华为meta60指导价格:" + integer.toString() + "   实时华为meta60价格:" + value.toString());
                                //业务判断逻辑
                                if (value > integer) {
                                    out.collect(value);
                                    System.out.println("    实时华为meta60:" + value.toString() + "超出官方指导价格告警!!!!");
                                }
                            }
                    }
                    @Override
                    //processElement 方法用于处理主流(Main Input)中的每个元素(事件)。主流通常包含实时数据,你可以在这个方法中对主流中的事件进行处理、转换或过滤,并生成输出。
                    public void processBroadcastElement(price value, BroadcastProcessFunction<Integer, price, Integer>.Context ctx, Collector<Integer> out) throws Exception {
//                        将广播流中的属性值传入到广播流中productPrices属性状态,put方法第一个参数传入key,第二个参数传入value
                        ctx.getBroadcastState(productPriceDescriptor).put(value.getA(),value.getB());
                    }

                });
        executionEnvironment.execute();
    }
}

        step1:创建普通主数据流和广播流

        step2:定义广播流的配置属性

MapStateDescriptor<String, Integer> productPriceDescriptor = new MapStateDescriptor<>("productPrices", String.class, Integer.class);

        step3:将普通主数据流和广播流进行connect,调用process方法,在process方法中通过自定义BroadcastProcessFunction继承的processElement方法和processBroadcastElement方法,分别对普通主数据流中事件和广播流中事件进行处理。

        step4:在processBroadcastElement方法中通过put传入key和value定义广播流配置属性值。

        step5:processElement方法中通过以下方法获取相应的广播配置属性值,并进行相关的业务逻辑处理:

//获取广播流中的属性状态
                        ReadOnlyBroadcastState<String, Integer> broadcastState = ctx.getBroadcastState(productPriceDescriptor);
                        //通过key获取广播流中的属性状态的值
                            Integer integer = broadcastState.get("华为meta60");

         总结来说,广播流类似一个辅助角色,能让主流在不停止的情况下,实时的将动态变化的值和主流连接,实现动态条件处理的效果。

猜你喜欢

转载自blog.csdn.net/qq_44540985/article/details/132989504