【FLink-7-Flink广播变量Broadcast】

FLink-7-Flink广播变量Broadcast

Flink广播变量Broadcast

把数据打宽

  • 1.Broadcast State 是 Flink 1.5 引入的新特性。 在开发过程中,如果遇到需要下发/广播配置、规则(关联字段表或者小的维表时)等低吞吐事件流到下游所有 task 时,就可以使用Broadcast State 特性。下游的 task 接收这些配置、规则并保存为 BroadcastState, 将这些配置应用到 另一个数据流的计算中 。

  • 2.在进行下发广播变量的时候,需要进行确认要进行广播的数据,以什么为key,什么为value。

  • 3.广播变量,两部分数据进行connect的时候,需要确认左边的数据流是否为keyedStream类型的数据流,如果是的话,选择KeyedBroadcastProcessFunction类型的广播方法,不是的话,选择没有keyd类型的BroadcastProcessFunction广播方法。

  • 4.两个流关联以后,会实现匿名内部类BroadcastProcessFunction的两个方法,但是这两个方法之间没有关联关系,需要使用FLink提供的状态管理机制来实现两个方法之间的数据共用,如果尝试自己书写状态机制管理数据的时候,就会出现宕机重启的时候,状态丢失的问题,持久化的话,自己书写一套逻辑,不如直接使用flink的状态管理机制:BroadcastState (ctx.getBroadcastState())
    在这里插入图片描述

  • 5.基于刚刚的flink的状态管理机制:BroadcastState (ctx.getBroadcastState()),如果此变量作为局部环境变量,在主流中也调用此状态,主流中仅仅使用get是没问题的,但是如果在主流中还进行set方法的话,因为此广播变量对应的是分布式环境,当前节点修改了,会导致其他节点数据不一致情况出现,所以需要使用主流中只读状态变量,下图这样用是不建议的:
    在这里插入图片描述

  • 6.正确的使用广播变量的方式,如下图:
    在这里插入图片描述

  • 7.具体代码示例如下:

package com.yang.flink.sideStream;

import org.apache.flink.api.common.state.BroadcastState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.CheckpointingMode;
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;

public class BroadcastDemo {
    public static void main(String[] args) {
        Configuration configuration = new Configuration();
        configuration.setInteger("rest.port", 8822);
        StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(configuration);
        env.setParallelism(1);


        // 开启checkpoint
        env.enableCheckpointing(5000, CheckpointingMode.EXACTLY_ONCE);
        env.getCheckpointConfig().setCheckpointStorage("file:///e:/ckptwangzhenguangshigedashabi");

        // 构造数据流1  socket传递来的数据格式为:id,name
        DataStreamSource<String> streamSource1 = env.socketTextStream("hadooop102", 9999);
        SingleOutputStreamOperator<Tuple2<String, String>> stream1 = streamSource1.map(s -> {
            String[] split = s.split(",");
            return Tuple2.of(split[0], split[1]);
        }).returns(new TypeHint<Tuple2<String, String>>() {});

        //构造数据流2  socket传递来的数据格式为:id,age,city
        DataStreamSource<String> streamSource2 = env.socketTextStream("hadoop102", 9998);
        SingleOutputStreamOperator<Tuple3<String, String, String>> stream2 = streamSource2.map(s -> {
            String[] split = s.split(",");
            return Tuple3.of(split[0], split[1], split[2]);
        }).returns(new TypeHint<Tuple3<String, String, String>>() {});

        /**
         * 广播变量的使用
         */
        MapStateDescriptor<String, Tuple2<String, String>> userInfoBroadcast = new MapStateDescriptor<>("userInfoStateDesc", TypeInformation.of(String.class), TypeInformation.of(new TypeHint<Tuple2<String, String>>() {
        }));
        BroadcastStream<Tuple3<String, String, String>> broadcastStream = stream2.broadcast(userInfoBroadcast);


        stream1.connect(broadcastStream).process(new BroadcastProcessFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {

            /**
             * 本方法,是用来处理 主流中的数据(每来一条,调用一次)
             * @param element  左流(主流)中的一条数据
             * @param ctx  上下文
             * @param out  输出器
             * @throws Exception
             */
            @Override
            public void processElement(Tuple2<String, String> element, ReadOnlyContext ctx, Collector<String> out) throws Exception {

                ReadOnlyBroadcastState<String, Tuple2<String, String>> broadcastState = ctx.getBroadcastState(userInfoBroadcast);

                if(broadcastState!=null){
                    Tuple2<String, String> userInfo = broadcastState.get(element.f0);
                    //代码健壮性,判空操作
                    out.collect(element.f0 + "," + element.f1 + "," + (userInfo == null ? null : userInfo.f0) + "," + (userInfo == null ? null : userInfo.f1));
                }else {
                    out.collect(element.f0+","+element.f1+ "," + null + "," + null);
                }
            }

            /**
             *
             * @param element  广播流中的一条数据
             * @param ctx  上下文
             * @param out 输出器
             * @throws Exception
             */
            @Override
            public void processBroadcastElement(Tuple3<String, String, String> element, Context ctx, Collector<String> out) throws Exception {

                // 从上下文中,获取广播状态对象(可读可写的状态对象)
                BroadcastState<String, Tuple2<String, String>> broadcastState = ctx.getBroadcastState(userInfoBroadcast);

                // 然后将获得的这条  广播流数据, 拆分后,装入广播状态
                broadcastState.put(element.f0,Tuple2.of(element.f1,element.f2));

            }
        });
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值