目前spark是一个非常流行的内存计算(或者迭代式计算,DAG计算)框架,在MapReduce因效率低下而被广为诟病的今天,spark的出现不禁让大家眼前一亮。
从架构和应用角度上看,spark是一个仅包含计算逻辑的开发库(尽管它提供个独立运行的master/slave服务,但考虑到稳定后以及与其他类型作业的继承性,通常不会被采用),而不包含任何资源管理和调度相关的实现,这使得spark可以灵活运行在目前比较主流的资源管理系统上,典型的代表是mesos和yarn,我们称之为“spark on mesos”和“spark on yarn”。
将spark运行在资源管理系统上将带来非常多的收益,包括:与其他计算框架共享集群资源;资源按需分配,进而提高集群资源利用率等。这篇文章主要介绍spark on yarn的技术挑战。
Spark on yarn在spark 1.0版本中已经变得比较成熟,但如果运行在线上环境中,仍面临很多挑战。
挑战1: 应用程序日志如何获取?
Spark on yarn提供了应用程序运行的web界面,可以通过这个界面查看spark作业的stage,task等详细信息,但无法获取应用程序的运行日志。这些日志通常保存在YARN的NodeManager节点上,一旦运行完成后可能会被聚集后保存到HDFS上。对于运行完成的作业,可以通过命令“bin/yarn logs -applicationId application_2323_xxxx”将日志打印出来,但是当日志量非常大时,显然不会很好地方法。因此,对于想把spark运行在yarn上的公司,第一个需要做的工作可能是为用户提供一个好的日志查看工具,可以查看正在运行的,或者运行完成(成功和失败)的spark作业的,在yarn-client和yarn-cluster模式下地日志。
挑战2:如何为spark作业设置资源需求?
YARN允许spark作业为driver和executor设置需要的cpu和内存资源量,但是到底设置多少最为合适,这显然不好确定。因此,最好能够提供一个资源获取工具,可以查看spark作业实际占用的内存和cpu资源量,以便修正用户的资源参数。
挑战3:yarn资源调度器对spark这类作业的水土不服
对于yarn而言,spark仍然是一种比较特殊的作业,这使得spark难以与其他类型的应用程序(比如mapreduce)友好地运行在一个集群中,主要体现在以下几个方面:
(1)YARN中的资源调度器采用的是基于资源预留的调度机制,这种机制会使得大资源需求的作业获取资源非常慢,而spark正是这类大资源需求的作业。正如我的文章“Apache Spark探秘:多进程模型还是多线程模型?”所述,Spark采用的是多线程方案,这使得一个executor可能会占用很大资源,这对于yarn而言,可能是资源利用率的灾难。
(2)YARN的这种资源预留机制在运行spark streaming作业时,可能产生饿死现象。如果你在yarn集群中运行了spark streaming作业,可能会产生资源无限预留但是永远得不到满足的情况,导致spark streaming作业用于得不到运行。这个在spark streaming与其他短类型的作业,比如spark和mapreduce作业共享集群时很容易发生。
为了解决资源调度问题,yarn已经在优化和改进中了,一个改进是每类作业增加一个作业标识(https://issues.apache.org/jira/browse/YARN-563),比如是长作业还是短作业,这样调度器更加智能的对不同类型作业进行调度;另外一个是改进现有的yarn的资源预留算法,其中一项工作见https://issues.apache.org/jira/browse/YARN-1769。
限于篇幅原因,这篇文章只介绍这三个问题,除此之外,还有很多其他问题,留在以后详细介绍。
总之,spark on yarn运行在生产环境中,仍有很多工作需要做,这个过程还是一个需求驱动的开发过程,即在使用过程中遇到问题,解决问题。