Spark Structured Streaming源码扩展--(六)流式Shuffle支持多分区及侧边输出

文章目录

  • 一、概述
  • 二、核心实现:CoordinatorEndpoint及SlaveEndpoint端点
    • 1、创建CoordinatorEndpoint分区位置存储端点
    • 2、SlaveEndpoint:RPC数据接收及分发端点
  • 三、侧边输出自动识别
  • 四、并发性能
  • 五、偏好设置

一、概述

上一篇文章,我们介绍了Spark Continous连续处理模式,已有流式shuffle的实现,分析了绑定的物理计划和内部创建的writer、reader。
在本文,我们将介绍如何扩展Spark Continous流式shuffle源码,以支持多个下游分区、侧边输出、自动分析侧边输出的依赖、删除ReceiverEpochMarker机制提高并发性能等原理。

Spark 流处理源码版本迭代较快,为了避免应用扩展功能与Spark源码过于耦合,增加Spark版本升级难度,拟在DataSourceV2Strategy处,增加策略的绑定,实现的大部分逻辑仍放在应用层代码org.apache.spark包路径下。

二、核心实现:CoordinatorEndpoint及SlaveEndpoint端点

在下图中DataCleanRDD表示数据清理数据(即Shuffle前数据), 通过我们设计的shuffle数据流向,被分发到api聚合流、host聚合流各分区对应queue中:
(除下图流式数据分发外,流式Dataset#repartition方法也可以通过DataSourceV2Strategy直接绑定这个shuffle策略,流式group by算子执行前的shuffle操作同理)

Spark Structured Streaming源码扩展--(六)流式Shuffle支持多分区及侧边输出_第1张图片

1、创建CoordinatorEndpoint分区位置存储端点

在driver增加ContinuousShuffleCoordinatorEndpoint(shuffle进度、元信息协调器)

  • 多个侧边输出间,应该具有相同的分区数和分区偏好,例如清洗后数据分发给下游多个流处理和分析,下游分区所在位置存储通过Coordinator来实现,参考了Spark源码中StateStoreCoordinator(增量缓存协调器)和OutputCommitCoordinator(写HDFS协调器)
  • 下游Node如果使用了form side_table关键字,分区创建后,自动向CoordinatorEndpoint汇报自身位置信息
  • 上游RDD(Continuous Shuffle Writer RDD)在shuffle分发数据前,查询CoordinatorEndpoint中具有的各下游分区位置信息,使用partitioner来决定某一条数据分发到哪个SlaveEndpoint
  • SlaveEndpoint(每个Executor一个SlaveEndpoint)可以对数据进行复制,放入message指定的多个队列,实现侧边输出(侧边输出的使用场景:数据清洗后产生300条数据,使用300次RPC分发到SlaveEndpoint,每条数据再被复制为两条,放入api、host命令流中进行后续计算)

2、SlaveEndpoint:RPC数据接收及分发端点

在每个executor增加ContinuousShuffleSlaveEndpoint,以RPC的方式接收消息

  • 这种设计方式,参考了Spark源码中BlockManagerMasterEndpoint与BlockManagerSlaveEnpoint块传输实现,每个Executor上只有一个接收消息的SlaveEndpoint端点,同时要考虑其数据复用(侧边输出)和并发性能。
  • SlaveEndpoint接收到消息时,根据消息标注的需要分发table partition列表,复制分发到对应队列中

三、侧边输出自动识别

  • 在微批处理(MicroBatchExecution)流计算中,我们使用了DistributeSink,DistributeSource来实现类似的侧边数据功能,中间数据以block方式存储在Spark BlockManager中,这种方式需要用户显示配置DistributeSink(数据清理输出流)、多个DistributeSource(下游数据消费流)
  • 在连续处理(ContinuousExecution)流计算中,我们使用了类似的方法,创建DistributeContinuousWriter,多个DistributeContinuousReader(自动关联到DistributeContinuousPartitionReader及SlaveEndpoint,参考了连续处理模式Kafka Reader的设计)

1、为了减少用户对Sink、Source及Writer、Reader的配置,我们考虑增加自动识别侧边数据:用户只需要指定某个table为side table,后续流程直接使用sql语句,select xxxx from side_table表述业务逻辑
2、在某个Node执行时,如果有 from side_table关键字,则会在.sql()初步执行后,分析自身逻辑计划,与 catalog中side_table所在逻辑计划进行替换匹配,替换为对应的Sink、Source(微批处理)或Writer、Reader(连续处理)

Spark Structured Streaming源码扩展--(六)流式Shuffle支持多分区及侧边输出_第2张图片

四、并发性能

  • Spark原生流式Shuffle,每个writer写完自己当前Epoch数据后,会发送一条ReceiverEpochMarker消息给下游,但是在多分区shuffle的应用场景下,如果上游10个分区,下游200个分区,则需要发送10x200 = 2000次数据(单分区是10x1 =10次数据),这个动作每隔100ms会发生一次,会产生非常多冗余通信数据
  • 为了避免上述现象的发生,我们通过分析多个流之间相同的依赖部分,将共同部分(例如数据清理),标记为SideTable,同时将其独立处理,创建一个单独的流(并创建标准ContinuousDataWriter),原有多个流,替换其SideTable对应部分逻辑执行计划,以ContinuousDataReader来代替,生成新的Sink、Source(或writer、reader)

五、偏好设置

下游多个流应该相同分区个数(推荐),这样,在使用HashPartitioner分发数据时,多个下游分区的数据可以合并分发(见本文概要图),只需要RPC发送一次,再将数据引用复制到不同队列中即可。
偏好设置及根据位置分发数据步骤:
1、设置下游ContinuousDataSourceRDD偏好,即用户实现的InputPartition(reader)偏好,例如partition_id % num_executor,得到executor偏好位置及host
2、 上一步设置分区偏好,在分区创建时,以(sink-name,partition-id,executor)注册到CoordinatorEndpoint中
3、上游Shuffle前RDD获取每个sink各分区所在位置,使用partitioner分发单条数据到对应SlaveEndpoint
4、SlaveEndpoint复制Message引用到两个(或多个)队列

你可能感兴趣的:(spark,structured,streaming源码)