在flink中,大多数state只作用于各自的算子,算子间不能共用state,BroadcastProcessFunction和KeyedBroadcastProcessFunction则作用于全局算子,进行数据共享,类似于spark中的广播变量,但只能在广播端进行数据的读写,非广播端只有读操作。如果DataStream需要使用广播流时,通过connect函数进行融合。
Broadcast State
Broadcast State是一个mapstate,所以Descriptor要创建为MapStateDescriptor
val ruleStateDescriptor = new MapStateDescriptor[JsonObject](
"RulesBroadcastState",
BasicTypeInfo.STRING_TYPE_INFO,
TypeInformation.of(new TypeHint[JsonObject]() {}))
val ruleBroadcastStream = dataStream.broadcast(ruleStateDescriptor)
BroadcastStream
可以通过调用connect()
非广播流(以keyBroadcastStream
为参数)来将流(keyDataStream或DataStream)与进行连接。这将返回一个BroadcastConnectedStream
,我们可以在其中调用process()
特殊类型的ProcessFunction
。该函数将包含我们的处理逻辑。函数的具体类型取决于非广播流的类型:
- 如果使用key,则该函数为
KeyedBroadcastProcessFunction
。 - 如果使用no-key,则该函数为
BroadcastProcessFunction
。
BroadcastProcessFunction和KeyedBroadcastProcessFunction
两种process function都含有processElement和processBroadcastElement方法,分别用来处理非广播元素和广播元素。不同点在于ctx方面,非广播方法有ReadOnlyContext(对广播元素只读,原因是在Flink中没有跨任务通信,保证Broadcast State在所有task中元素相同,保证state一致性),广播方法有Context。
public abstract class BroadcastProcessFunction<IN1, IN2, OUT> extends BaseBroadcastProcessFunction {
public abstract void processElement(IN1 value, ReadOnlyContext ctx, Collector<OUT> out) throws Exception;
public abstract void processBroadcastElement(IN2 value, Context ctx, Collector<OUT> out) throws Exception;
}
public abstract class KeyedBroadcastProcessFunction<KS, IN1, IN2, OUT> {
public abstract void processElement(IN1 value, ReadOnlyContext ctx, Collector<OUT> out) throws Exception;
public abstract void processBroadcastElement(IN2 value, Context ctx, Collector<OUT> out) throws Exception;
public void onTimer(long timestamp, OnTimerContext ctx, Collector<OUT> out) throws Exception;
}
两个ctx有共同属性:
- 允许访问广播状态:
ctx.getBroadcastState(MapStateDescriptor<K, V> stateDescriptor)
- 允许查询元素的时间戳:
ctx.timestamp()
- 得到当前的水印:
ctx.currentWatermark()
- 获得当前处理时间:
ctx.currentProcessingTime()
- 将元素进行侧输出:
ctx.output(OutputTag<X> outputTag, X value)