Spark学习笔记(四)

为什么理解Spark内部?

目标:查找每个“第一个字母”的不同名称的数量
给出一种代码:
sc.textFile(“hdfs:/names”)
.map(name => (name.charAt(0), name))
.groupByKey()
.mapValues(names => names.toSet.size)
.collect()
1
2
最后执行结果:
3

Spark执行模型
1.创建RDD的DAG以表示计算
2.为DAG创建逻辑执行计划
3.计划和执行单个任务

步骤1:创建RDD

HadoopRDD -> map() -> groupBy() -> mapValues() -> collect()

步骤2:创建执行计划(尽可能地Pipeline,根据需要重新组织数据,分成“Stage”)
11
( 一般是在shuffle的步骤下进行Stage的划分)
步骤3: 分派任务

  • 将每个阶段分成任务
  • 任务是数据+计算
  • 执行前一个阶段中的所有任务
    22

33

Shuffle

  • 在分区之间重新分配数据
  • 将密钥哈希到桶中
  • 优化:
    • 如果数据已经正确分区,尽可能避免
    • 部分聚合减少了数据移动
    • 将中间文件写入磁盘
      5

执行groupBy()

  • 在每个分区中构建散列映射
    • A => [Arsalan, Aaron, Andrew, Andrew, Andy, Ahir, Ali, …],
    • E => [Erin, Earl, Ed, …]
  • 注意:可以跨键,但单个键值对必须不超过内存大小

从spark内核角度的思考

优化方向
- 分区没有获得良好的并发性
- 键组过大
- 在集群中运送所有数据

常见问题清单
1.确保有足够的分区用于并发
2.最小化内存消耗(特别是groupBys中的排序和大键)
3.最小化数据混洗的数量
1&2是关于调整分区数!

分区调优的重要性
•主要问题:分区过少
- 减少并发
- 更易受数据偏移的影响
- 增加了groupBy,reduceByKey,sortByKey等的内存压力。
•次要问题:分区过多
•需要“合理数量”的分区
- 通常在100到10,000个分区之间
- 下限:集群中至少〜2×数量的核
- 上限:确保任务至少需要100ms

内存问题
•症状:
- 不可思议的性能表现不佳
- 无法解释的执行器/机器故障“
•诊断:
- 设置spark.executor.extraJavaOptions包括
•-XX:+ PrintGCDetails
•-XX:+ HeapDumpOnOutOfMemoryError
- 检查dmesg的oom-killer日志
• 措施:
- 增加spark.executor.memory
- 增加分区数
- 重新评估程序结构(!)

sc.textFile(“hdfs:/names”)
.distinct(numPartitions = 6)
.map(name => (name.charAt(0), name))
.groupByKey()
.mapValues { names => names.size }
.collect()

sc.textFile(“hdfs:/names”)
.distinct(numPartitions = 6)
.map(name => (name.charAt(0), 1))
.reduceByKey(_ + _)
.collect()

在Shuffle之前对数据进行distinct,同时设置合理的分区数量,在设置key-value中的value时,直接置为1,再利用.reduceByKey(_ + _)直接得到结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值