Flink DataSet API 之 Broadcast(广播变量)

本文深入探讨了Flink广播变量的原理与应用,包括其如何提高数据处理效率,避免重复数据传输,以及如何在集群中共享只读数据集。通过具体示例展示了广播变量的初始化、广播和获取过程,强调了其在内存管理和数据一致性上的注意事项。

基本介绍

1、广播变量允许编程人员在每台机器上保持1个只读的缓存变量,而不是传送变量的副本给tasks

2、广播变量创建后,它可以运行在集群中的任何function上,而不需要多次传递给集群节点。另外需要记住,不应该修改广播变量,这样才能确保每个节点获取到的值都是一致的。可以理解为是一个公共的共享变量,我们可以把一个dataset 数据集广播出去,然后不同的task在节点上都能够获取到,这个数据在每个节点上只会存在一份。如果不使用broadcast,则在每个节点中的每个task中都需要拷贝一份dataset数据集,比较浪费内存(也就是一个节点中可能会存在多份dataset数据)。

3、与DataStreaming 中的Broadcast区别开来,DataStreaming 中的Broadcast是把元素广播给所有的分区,数据会被重复处理,类似于storm中的allGrouping(调用方式 dataStream.broadcast())

用法

1:初始化数据       DataSet<Integer> toBroadcast = env.fromElements(1, 2, 3)

2:广播数据           withBroadcastSet(toBroadcast, "broadcastSetName");

3:获取数据           Collection<Integer> broadcastSet = getRuntimeContext().getBroadcastVariable("broadcastSetName");

注意

1:广播出去的变量存在于每个节点的内存中,所以这个数据集不能太大。因为广播出去的数据,会常驻内存,除非程序执行结束

2:广播变量在初始化广播出去以后不支持修改,这样才能保证每个节点的数据都是一致的。

使用Demo

import org.apache.flink.api.common.functions.RichMapFunction
import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.configuration.Configuration

import scala.collection.mutable.ListBuffer

object BatchDemoBroadcast {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment
    import org.apache.flink.api.scala._
    // 1、初始化数据
    val broadData = new ListBuffer[Tuple2[String, Int]]()
    broadData.append(("zs", 18))
    broadData.append(("ls", 20))
    broadData.append(("ww", 17))
    val tupleData = env.fromCollection(broadData)
    val toBroadcastData = tupleData.map(data => Map(data._1 -> data._2))

    val text = env.fromElements("zs", "ls", "ww")
    text.map(new RichMapFunction[String, String] {
      var allMap  = Map[String,Int]()
      override def open(parameters: Configuration): Unit = {
        super.open(parameters)
        // 3、获取数据
        val listData = getRuntimeContext.getBroadcastVariable[Map[String,Int]]("broadcastData")
        val it = listData.iterator()
        println("-------------------")
        while (it.hasNext) {
          allMap = allMap.++(it.next())
        }
      }

      override def map(in: String): String = {
        in + "_" + allMap(in)
      }
    }).withBroadcastSet(toBroadcastData, "broadcastData")// 2、广播数据
      .print()
  }
}

 

在 Apache Flink 中,**广播Broadcast)** 是一种将**同一份数据分发给所有并行子任务**的机制,常用于广播配置、规则、状态等全局信息。 --- ## ✅ Flink 广播是 **TaskManager 级别** 的吗?还是 **Slot 级别** 的? ### 答案是: > **Flink广播是基于 Operator 级别,并且是每个并行子任务(每个 Slot)都独立拥有一份副本。** 所以,**广播是 Slot 级别的**,每个 Slot(即每个并行子任务)都会收到一份广播变量的副本。 --- ## ✅ 广播机制详解 Flink广播机制主要通过两种方式实现: ### 1. **Broadcast State(广播状态)** 这是 Flink 状态编程中的一种特殊状态类型,用于将一个流的事件广播到所有子任务,并与另一个流进行处理。 #### 示例代码(Broadcast + ProcessFunction): ```java // 定义广播流(如规则流) BroadcastStream<Rule> broadcastRuleStream = ruleStream .broadcast(new MapStateDescriptor<>("rules", String.class, Rule.class)); // 主数据流连接广播流 dataStream .connect(broadcastRuleStream) .process(new BroadcastProcessFunction<Data, Rule, Output>() { // 处理主数据流和广播数据流 }) .print(); ``` #### 广播行为说明: - **每条广播消息会被发送到下游所有并行子任务(Slot)** - 每个子任务(Slot)都会维护一份自己的广播状态(MapState) - 每个 Slot 独立更新和处理广播状态,互不干扰 --- ### 2. **使用 `RichFunction` 的 `open()` 方法广播变量(老式方式)** 你也可以在 `RichMapFunction` 或 `RichFlatMapFunction` 中使用 `getRuntimeContext().getBroadcastVariable()`,但这只适用于 **DataSet API**(批处理),不适用于 DataStream。 #### 示例(DataSet API): ```java DataSet<String> data = ...; DataSet<Integer> broadcastData = ...; data.map(new RichMapFunction<String, String>() { private List<Integer> broadcastList; public void open(Configuration parameters) { broadcastList = getRuntimeContext().getBroadcastVariable("broadcastName"); } public String map(String value) { // 使用 broadcastList return value + broadcastList.toString(); } }).withBroadcastSet(broadcastData, "broadcastName"); ``` #### 广播行为说明: - 每个 TaskManager 会收到一次广播数据 - 但每个 Slot(即每个并行子任务)**在运行时都会访问 TaskManager 上的同一份广播变量副本** - 所以它是 **TaskManager 级别** 的共享,但不是每个 Slot 都独立复制一份 --- ## ✅ 总结对比 | 特性 | Broadcast State(DataStream) | Broadcast Variable(DataSet) | |------|-------------------------------|--------------------------------| | API 类型 | DataStream API(流处理) | DataSet API(批处理) | | 广播粒度 | 每个 Slot(每个子任务)独立保存一份 | 每个 TaskManager 共享一份 | | 状态更新 | 可动态更新 | 不支持动态更新 | | 用途 | 实时广播规则、配置等 | 批处理中广播静态数据 | | 线程安全 | 每个 Slot 独立,线程安全 | 多 Slot 共享,需自行同步 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值