Standalone模式
- Standalone 模式下有四个重要组成部分,分别是:
- Driver:用户编写的 Spark 应用程序就运行在 Driver 上,由Driver 进程执行
- Master:主要负责资源的调度和分配,并进行集群的监控等职责
- Worker:Worker 运行在集群中的一台服务器上。负责管理该节点上的资源,负责启动启动节点上的 Executor
- Executor:一个 Worker 上可以运行多个 Executor,Executor通过启动多个线程(task)对 RDD 的分区进行并行计算
SparkContext 中的三大组件:
- DAGScheduler:负责将DAG划分成若干个Stage
- TaskScheduler:将DAGScheduler提交的 Stage(Taskset)进行优先级排序,再将task 发送到 Executor
- SchedulerBackend:定义了许多与Executor事件相关的处理,包括:新的executor注册进来的时候记录executor的信息,增加全局的资源量(核数);executor更新状态,若任务完成的话,回收core;其他停止executor、remove executor等事件
Standalone模式下作业提交步骤
- 启动应用程序,完成SparkContext的初始化
- Driver向Master注册,申请资源
- Master检查集群资源状况。若集群资源满足,通知Worker启动Executor
- Executor启动后向Driver注册(称为反向注册)
- Driver完成DAG的解析,得到Tasks,然后向Executor发送Task
- Executor 向Driver汇总任务的执行情况
- 应用程序执行完毕,回收资源
Shuffle原理
- Spark、Hadoop中的shuffle可不是为了把数据弄乱,而是为了将随机排列的数据转换成具有一定规则的数据。
- Shuffle是MapReduce计算框架中的一个特殊的阶段,介于Map 和 Reduce 之间。当Map的输出结果要被Reduce使用时,输出结果需要按key排列,并且分发到Reducer上去,这个过程就是shuffle。
- shuffle涉及到了本地磁盘(非hdfs)的读写和网络的传输,大多数Spark作业的性能主要就是消耗在了shuffle环节。因此shuffle性能的高低直接影响到了整个程序的运行效率
- 在Spark Shuffle的实现上,
RDD编程优化
- 对于同一份数据,只应该创建一个RDD,不要创建多个RDD来代表同一份数据。
- RDD缓存/持久化:当多次对同一个RDD执行算子操作时,每一次都会对这个RDD以之前的父RDD重新计算一次,避免对同一个RDD的重复计算
- 对多次使用的RDD进行持久化,通过持久化将公共RDD的数据缓存到内存/磁盘中,之后对于公共RDD的计算都会从内存/磁盘中直接获取RDD数据
- RDD的持久化是可以进行序列化的,当内存无法将RDD的数据完整的进行存放的时候,可以考虑使用序列化的方式减小数据体积,将数据完整存储在内存中
- 尽可能早的执行filter操作,过滤无用数据,在filter过滤掉较多数据后,使用 coalesce 对数据进行重分区
使用高性能算子
- 避免使用groupByKey,根据场景选择使用高性能的聚合算子 reduceByKey、aggregateByKey
- coalesce、repartition,在可能的情况下优先选择没有shuffle的操作
- foreachPartition 优化输出操作
- map、mapPartitions,选择合理的选择算子,mapPartitions性能更好,但数据量大时容易导致OOM
- 用 repartitionAndSortWithinPartitions 替代 repartition + sort 操作
- 合理使用 cache、persist、checkpoint,选择合理的数据存储级别
设置合理的并行度
- Spark作业中的并行度指各个stage的task的数量
- 设置合理的并行度,让并行度与资源相匹配。简单来说就是在资源允许的前提下,并行度要设置的尽可能大,达到可以充分利用集群资源。合理的设置并行度,可以提升整个Spark作业的性能和运行速度
广播大变量
- 默认情况下,task中的算子中如果使用了外部变量,每个task都会获取一份变量的复本,这会造多余的网络传输和内存消耗
- 使用广播变量,只会在每个Executor保存一个副本,Executor的所有task共用此广播变量,这样就节约了网络及内存资源