FLink-7-Flink广播变量Broadcast
- 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));
}
});
}
}