Spark Core调优
一、任务监控
(一)日志信息持久化配置
每一个SparkContext会在默认端口4040启动一个WebUI,用于展示Application一些有用的信息,包括:
- Stage和Tasks的调度
- RDD的大小和内存使用的情况
- 环境信息
- 正在运行的Executors的信息
但是注意的是,这些信息仅仅是在Application运行期间,你可以通过4040端口去访问,一旦Application运行结束就无法访问了。比如,进入/root/app/spark-2.0.2-bin-hadoop2.6/bin,提交脚本执行:
[root@hadoop-master bin]# ./spark-submit --master local[2] --name test_monitoring /root/hadoopdata/test_monitoring.py
from pyspark import SparkConf,SparkContext def getsc(): # 创建SparkConf,进行Spark配置 conf = SparkConf().setMaster("local[2]").setAppName("sparktest") # 创建SparkContext sc = SparkContext(conf=conf) return sc def my_actions(): data = [1,2,3,4,5] sc = getsc() rdd1 = sc.parallelize(data) rdd2 = rdd1.map(lambda x:x+1) print(rdd2.collect()) #[2, 3, 4, 5, 6] sc.stop() if __name__ == '__main__': my_actions()
在运行过程中可以进入WebUI界面进行查看,一旦执行完毕就无法查看了,如果你执行的时定时任务,第二天想查看日志都是无法查看的,此时应该怎么做呢?我们可以将历史日志信息进行持久化。
1、 spark-defaults.conf
在/root/app/spark-2.0.2-bin-hadoop2.6/conf目录下:
[root@hadoop-master conf]# cp spark-defaults.conf.template spark-defaults.conf #拷贝一份配置文件
vim spark-defaults.conf
... """ 放开以下配置,日志信息以及将其持久化存储在hdfs上 “”“ spark.eventLog.enabled true spark.eventLog.dir hdfs://hadoop-master:8020/directory ...
2、spark-env.sh
在/root/app/spark-2.0.2-bin-hadoop2.6/conf目录下:
vim spark-env.sh
... """ 进行history server的配置,文件系统的历史日志信息提供者,它的URL包含了加载Application的event logs ”“” SPARK_HISTORY_OPTS="-Dspark.history.fs.logDirectory=hdfs://hadoop-master:8020/directory" ...
3、启动hdfs
这是history logs实际持久化的地方
进入/root/app/hadoop-2.6.1/sbin,执行:
[root@hadoop-master sbin]# ./start-dfs.sh
然后创建目录directory
[root@hadoop-master sbin]# hadoop fs -mkdir /directory
(二)测试
1、启动history server
进入/root/app/spark-2.0.2-bin-hadoop2.6/sbin,然后执行:
[root@hadoop-master sbin]# ./start-history-server.sh
history的WebUI默认的访问端口为18080:

2、执行脚本
进入/root/app/spark-2.0.2-bin-hadoop2.6/bin,执行:
[root@hadoop-master bin]# ./spark-submit --master local[2] --name test_monitoring /root/hadoopdata/test_monitoring.py
在执行日志中有这样的信息:
...
20/04/19 10:01:32 INFO scheduler.EventLoggingListener: Logging events to hdfs://hadoop-master:8020/directory/local-1587261690162
...
说明已经将日志信息写入到hdfs中了,你可以去查看。此时我们再刷新一下history server启动的WebUI界面:

已经有日志信息了。
二、序列化
序列化在分布式应用程序中扮演着重要角色,通常这是spark应用程序优化的第一步,spark提供了两种方式:
- Java serialization 这是spark应用程序默认的序列化方式,这种序列化方式是很灵活的但是却相对较慢
- Kryo serialization 这种序列化方式会更快,但是这种序列化方式不支持所有的序列化类型、以及你需要事先将你应用程序中的类进行注册
三、内存管理
1、内存管理概述
在Spark中,内存的使用大体包括两种情况:
- execution
- storage
一般在shuffles, joins, sorts and aggregations这些情况下会造成execution的内存使用;另外在集群中进行数据缓存以及内部变量的传递时会造成storage的内存使用, execution和storage共享同一块区域。当execution的内存没有被使用时,storage可以获取所有的可用内存(包括本属于execution的那部分内存),同理execution也是一样。除非execution或者storage设置了它自己的最少的可用空间。
spark有内存的默认配置,用户一般情况下是不需要调整它们的:
- spark.memory.fraction 它的大小是(JVM heap space-300M)*0.6,剩余的40%用于保留用于用户数据结构,Spark中的内部元数据,并在记录稀疏和异常的情况下防止OOM错误。
- spark.memory.storageFraction 表示
R作为M的一部分(默认为0.5)。R包含着不受Execution所驱逐的缓存M块。
2、内存消耗
如何查看一个数据集比如RDD消耗了多少内存呢?最好的方式是通过看WebUI上Storage参数:

另外还可以通过一种方式,使用SizeEstimator’s estimate方法去查看内存消耗的多少。当你觉得你的数据集占用太大的空间,可以考虑去Serialized RDD进行存储。
四、广播变量
1、什么是广播变量
广播变量是允许开发者将只读变量缓存到每一台机器中而不是将变量拷贝到每一个Task中。这样的话如果某台机器上很多Task需要用这个变量,直接从机器中去获取这个关闭广播变量,避免了将变量拷贝到每一个Task造成空间的浪费。
在python中,可以这样写:
>>> broadcastVar = sc.broadcast([1, 2, 3]) <pyspark.broadcast.Broadcast object at 0x102789f10> >>> broadcastVar.value [1, 2, 3]
2、注意事项
在广播变量使用中需要注意以下几点:
- 如果单个Task的大小大于20KB可以考虑将其进行优化
- 使用广播变量可以大大降低序列化任务的大小
- 如果Task中使用很大的对象,可以考虑将其转化为广播变量
五、数据本地性
数据本地性在Spark jobs中有着很大的影响,如果data和code是在一台机器上的话,进行计算是很快的。但是如果data和code是在不同的机器上的话,通常移动code到data那台机器上比移动data到code的机器上计算要快很多,因为code比data的大小要小很多。那么数据本地性如何保证data更加的靠近code呢?
这里有几种本地性的策略:
- PROCESS_LOCAL data和code是在同一节点上运行,这是最好的方式
- NODE_LOCAL data在同一节点上。可能在同一节点上的HDFS中,或者在同一节点上的另一执行程序中。这比PROCESS_LOCAL要慢一些,因为data必须在进程之间传输
- NO_PREF data可以从任何地方快速的被访问而没有位置局限
- RACK_LOCAL data是在同一个机架上的不同服务器上,需要通过网络传递
- ANY data在不同的机架上,并且在同一网络上的其它位置
Spark优先去调度去调度上述最好的策略来执行所有的Tasks,但是最好的策略不可能总是有适用场景的,所以当一个最好的策略没有适用场景时,会选择低一个级别的策略来执行Tasks,依次类推。
每一个策略的切换需要等待时间,这个时间是可以通过参数spark.locality.wait进行调节的,默认的时间是3s。
参考:http://spark.apache.org/docs/2.0.2/tuning.html


浙公网安备 33010602011771号