从0到1进行Spark history分析( 二 )


(五)查看相关代码段1.定位异常Job通过applicationID进入到我们要分析的Job的运行情况页面后 , 可以看到该App ID下每一个Job , 一般通过观察每一个Job的运行时长可以识别出哪一个Job是异常的 , 通常运行时间过长的Job就是异常的 , 可以进入该Job的详细页面进行进一步分析 。
2.回溯Job对应代码段一般定位到异常的Job我们就可以知道对应的代码段 , 通常这个Job运行情况页会显示其对应的代码行 , 通过回到代码中找到这个代码行 , 其前后一小部分代码段就是这个异常Job的执行代码段 。
(六)分析与定位问题1.列出代码段涉及的源表如果是SparkSQL代码 , 可以通过SQL直观获取到其所涉及的源表 , 将这些源表记录下来 , 以便后续分析 。
如果是SparkRDD代码 , 可以通过代码中所使用的数据集追溯到该数据集所对应的源表 , 同样 , 我们把它们记录下来 , 以便后续进行分析 。
2.分析源表的使用方式:广播、普通关联、…我们可以通过代码中分析出这些源表的使用方式 。 最常见的应该是对小表进行广播的方式 。 所谓广播 , 就是把小表的数据完整地发送到集群的各个DataNode本地缓存起来 , 当大表与之进行关联操作时 , 存在于各个DataNode之上的大表数据块便可以根据就近计算原则 , 与小表数据进行关联计算 , 从而减少了网络传输 , 提高了运行速度 。
在SparkSQL中 , 一般如果大表和小表进行关联 , 会通过hint语法对小表进行广播 , 具体来说是使用 /*mapjoin(small_table_name)*/ 这样的形式 。
而在SparkRDD中 , 一般也会对小表进行广播操作 , 通过broadcast()接口进行实现 。 在Java中,具体来说是使用Broadcast data_broadcast = JavaSparkContext.broadcast(table_data.collect());这样的语法进行实现 。
对于普通关联 , 即没有对表进行特殊处理的关联 。 这种写法一般在大小表关联的场景下容易出现性能问题 , 需要特别关注 。 经常可以作为问题分析的切入点 。
3.查看源表数据量一般通过第一步把问题代码段中所涉及的源表罗列出来后 , 就需要到生产查看这些源表的数据量是多少 , 以方便分析是否是因为数据量过大而导致的性能问题 , 一般如果是数据量导致的问题 , 多半是因为资源不足 , 可以考虑通过调整资源数量来解决 。
当然 , 除了常规的查看源表的记录数外 , 还可以查看该表在HDFS上占用的空间大小 。
查看源表记录数SQL:
select count(1) as cnt from db_name.table_name where pt_dt=’xxxx-xx-xx’;查看源表占用的空间大小 , 这里使用GB为单位(1024 1024 1024)显示:
hadoop fs -du /user/hive/warehouse/db_name.db/ table_name/pt_dt='xxxx-xx-xx' | awk ‘${SUM+=$1} END {print SUM/(1024*1024*1024)}'4.查看源表数据块分布情况有时候源表的数据量并不算大 , 但是还是出现了性能瓶颈 , 这时候通过观察tasks数的多少 , 大致可以猜测到是因为源表的数据块大小分布不均匀 , 或是数据块过少导致的 。 可以通过以下命令查看源表的数据块分布情况:
hadoop fs -ls -h /user/hive/warehouse/db_name.db/ table_name/pt_dt='xxxx-xx-xx'通过该命令的输出我们可以看到源表的每一个数据块大小 , 以此有多少个数据块 。 举个例子 , 如果数据块只有2~3块 , 第一个数据块有80MB , 第二、第三个数据块分别只有1KB , 那基本可以判定这几个数据块分布不合理 。
数据块分布不合理可以通过对源表数据进行重分布(repartition)或设置spark处理的每个map数据块大小上限来前置将过大的数据块分散到各个task中处理 , 以减少关键task的处理耗时 , 提升程序性能 。
三、总结本文深入浅出 , 具体到步骤和实际操作 , 带领大家从获取作业applicationID , 到下载Spark history , 再到上传Spark history至开发环境 , 再进行Spark WebUI分析异常stage , 再而定位到问题代码段 , 最后给出一般问题的分析方向以及分析方法 。