【问题标题】:In spark, how does broadcast work?在 Spark 中,广播是如何工作的?
【发布时间】:2017-04-02 19:11:40
【问题描述】:

这是一个非常简单的问题:在 spark 中,broadcast 可以用来高效地将变量发送给执行器。这是如何工作的?

更准确地说:

  • 什么时候发送值:只要我打电话给broadcast,或者什么时候使用这些值?
  • 数据到底发送到了哪里:发送给所有执行者,还是只发送给需要它的人?
  • 数据存储在哪里?在内存中,还是在磁盘上?
  • 简单变量和广播变量的访问方式有区别吗?当我调用 .value 方法时,底层会发生什么?

【问题讨论】:

    标签: apache-spark hadoop2 bigdata


    【解决方案1】:

    简答

    • 值在执行程序第一次需要时发送。调用 sc.broadcast(variable) 时不会发送任何内容。
    • 数据仅发送到包含需要它的执行程序的节点。
    • 数据存储在内存中。如果没有足够的可用内存,则使用磁盘。
    • 是的,访问局部变量和广播变量之间有很大的不同。广播变量必须在第一次访问时下载。

    长答案

    答案在 Spark 的源代码中,TorrentBroadcast.scala

    1. sc.broadcast 被调用时,一个新的TorrentBroadcast 对象将从BroadcastFactory.scala 实例化。在初始化 TorrentBroadcast 对象时调用的writeBlocks() 中发生以下情况:

      1. 对象使用MEMORY_AND_DISK 策略在本地缓存,未序列化。
      2. 已序列化。
      3. 序列化版本被拆分为 4Mb 块,这些块被压缩[0],并保存在本地[1]
    2. 当新的执行器被创建时,它们只有轻量级的TorrentBroadcast 对象,它只包含广播对象的标识符,以及它的块数。

    3. TorrentBroadcast 对象具有包含其值的惰性[2] 属性。当调用value 方法时,会返回这个惰性属性。所以第一次在任务上调用这个值函数时,会发生以下情况:

      1. 以随机顺序从本地块管理器获取块并解压缩。
      2. 如果它们不在本地块管理器中,则在块管理器上调用getRemoteBytes 来获取它们。 网络流量发生仅在那个时候。
      3. 如果该块不存在于本地,则使用 MEMORY_AND_DISK_SER 对其进行缓存。

    [0] 默认使用 lz4 压缩。 This can be tuned.

    [1] 块存储在本地block manager,使用MEMORY_AND_DISK_SER,这意味着它将不适合内存的分区溢出到磁盘。每个块都有一个唯一标识符,由广播变量的标识符及其偏移量计算得出。块大小can be configured;默认为 4Mb。

    [2] scala 中的 lazy val 是一个变量,它的值在第一次访问时被评估,然后被缓存。 See the documentation.

    【讨论】:

    • 如果广播变量被发送到每个单独的集群节点(需要它),那么当我们不将其设为广播变量时​​有什么区别。否则将如何处理该变量?
    • 否则,变量将作为任务的一部分独立发送到每个执行程序,而不使用种子机制。如果变量很大,那么这会使任务变大,并延迟它的执行。而且不使用torrent协议意味着下载会更慢。
    • 还是没听懂。单独发送给每个执行者(在广播的情况下)和发送给每个集群节点(正常方式)有什么区别?
    • > 如果是非广播变量,则在分发任务时将其分发给每个执行者 [...] 。而在广播的情况下,一旦主分发它,接收执行者也充当分发者 [...] 是否正确理解?是的
    • 无论如何,您都将分发序列化的任务。如果任务开始时变量将立即可用,那么使任务重几个字节是值得的。但是当一个变量的值很大的时候,不带值的启动任务,然后通过bittorrent取值就变得值得了。
    【解决方案2】:
    • 一经播出
    • 它使用 torrent 协议发送给所有执行器,但仅在需要时加载
    • 一旦加载的变量被反序列化存储在内存中
    • 它:

      • 验证广播没有被破坏
      • 从 blockManager 中延迟加载变量

    【讨论】:

    • 我找到了来源,目前很难理解。在TorrentBroadcast.scala 中,它似乎告诉blockmanager 在创建Broadcast 时仅在本地写入字节,并且仅在调用value 时才发生网络传输。 (value 读取 _value,这是一个惰性验证)。这将意味着与您所说的完全相反:创建变量时不会发送任何内容,并且该值仅发送给需要它的执行程序。
    猜你喜欢
    • 2018-12-24
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多