Spark任务划分、代码执行位置、创建Connect连接的最佳实践

鸣谢:如果您觉得本文对您有帮助,请点赞和收藏,Thanks。

Spark任务划分

在RDD中,任务可切分为:Application、Job、Stage、Task

Application:初始化一个SparkContext即生成一个Application,通常一个main函数就是一个Application;

Job:一个Action算子就会生成一个Job,常用Action算子包括reduce、aggregate、collect、first、take、foreach、saveAsTextFile:saveAsTextFile、countByKey 、collectAsMap等等;

Stage:根据RDD之间的依赖关系的不同将Job划分成不同的Stage,遇到一个宽依赖则划分一个Stage,宽依赖指一个分区的数据会被划分到多个分区中去,这种会引发shuffle,比如groupBy操作;

Task:Stage是一个TaskSet(任务集),将Stage划分的结果发送到不同的Executor执行即为一个Task。

Application->Job->Stage-> Task
每一层都是1对n的关系。

Spark代码运行位置

Spark代码运行,分为Driver(驱动器)Executor(执行器)
通常来说,rdd算子中的代码在excuter执行,而其他代码都是在driver执行,并且只执行一次。
在这里插入图片描述

创建Connect连接的最佳实践

此处,以kafka流处理为例:消费spark streamign 消费kafka后,会产生一个DStream,要把数据输出到外面,创建连接对象的位置显示尤为重要。
通常,新手容易犯下以下错误:

1.在driver创建连接对象

dstream.foreachRDD { rdd =>
  val connection = createNewConnection()  // executed at the driver
  rdd.foreach { record =>
    connection.send(record) // executed at the worker
  }
}

这是错误的做法,因为这要求将连接对象序列化并从driver驱动程序发送给worker工作程序。这样的连接对象很少能在机器之间转移。此错误可能表现为序列化错误(连接对象不可序列化:connection object not serializable),初始化错误(连接对象需要在工作程序中初始化:connection object needs to be initialized at the workers)等。

2.在excuter创建对象

dstream.foreachRDD { rdd =>
 rdd.foreach { record =>
   val connection = createNewConnection()
   connection.send(record)
   connection.close()
 }
}

这种做法没有错,但是,创建连接对象会浪费时间和资源。因此,为每个记录创建和销毁连接对象会导致不必要的高开销,并且会大大降低系统的整体吞吐量。所以,不要使用这种办法创建连接对象。

正确创建连接的办法:

stream.foreachRDD { rdd =>
  rdd.foreachPartition { partitionOfRecords =>
    val connection = createNewConnection()
    partitionOfRecords.foreach(record => connection.send(record))
    connection.close()
  }
}

这种做法使用 rdd.foreachPartition创建单个连接对象,就是一个分区创建一个连接对象。
当然,还可以做以下优化:
建一个静态的、慢加载的连接对象池,按需延迟创建池中的连接,如果一段时间不使用,则归还连接对象。

dstream.foreachRDD { rdd =>
  rdd.foreachPartition { partitionOfRecords =>
    // ConnectionPool is a static, lazily initialized pool of connections
    val connection = ConnectionPool.getConnection()
    partitionOfRecords.foreach(record => connection.send(record))
    ConnectionPool.returnConnection(connection)  // return to the pool for future reuse
  }
}

备注:通过SparkSQL/SparkStreaming读写Hive/Mysql/Hbase/Kafka的代码模板可参考我的这篇文章
SparkSQL/SparkStreaming读写Hive/Mysql/Hbase/Kafka

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark任务的详细执行流程如下: 1. 创建SparkContext:首先,Spark应用程序需要创建一个SparkContext对象,它是与集群通信的主要入口点。 2. 创建RDD:在Spark中,数据被组织成弹性分布式数据集(RDD)。RDD可以从外部存储系统(如HDFS)中读取数据,也可以通过对已有RDD进行转换操作来创建。 3. 转换操作:Spark提供了一系列转换操作,如map、filter、reduce等。这些操作可以对RDD进行转换,生成新的RDD。转换操作是惰性求值的,即不会立即执行,而是记录下来以便后续执行。 4. 行动操作:当需要从RDD中获取结果时,需要执行行动操作。行动操作会触发Spark作业的执行,并将结果返回给驱动程序。 5. 任务划分Spark将作业划分为一系列任务,每个任务处理RDD的一个分区。任务划分是根据数据的分区情况和可用的计算资源进行的。 6. 任务调度:Spark任务调度到集群中的可用计算节点上执行任务调度器负责将任务分配给可用的Executor,并监控任务执行情况。 7. 任务执行:每个Executor会为分配给它的任务创建一个或多个线程,并在这些线程上执行任务任务执行过程中,Executor会将数据从内存或磁盘中读取到计算节点上,并进行计算操作。 8. 数据传输:在任务执行过程中,Spark会根据需要将数据从一个节点传输到另一个节点。这种数据传输可以是节点内的数据传输,也可以是跨节点的数据传输。 9. 结果返回:当任务执行完成后,结果会返回给驱动程序。驱动程序可以将结果保存到外部存储系统,或者进行进一步的处理和分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值