去年10月,我们实现了Spark1.5.2版本运行在Mesos这个资源管理框架上。随后Spark出了新版本我们又对Spark进行了小升级,升级并没有什么太大的难度,沿用之前的修改过的代码重新编译,替换一下包,把历史任务全部发一遍就能很好的升级到1.6.1也就是现在集群的版本,1.6.2并没有升级因为感觉改动不是很大。到现在正好一年的时间,线上已经注册了44个Spark任务,其中28个为Streaming任务,在运行这些任务的过程中,我们遇到了很多问题,其中最大的问题是动态扩容问题,即当业务线增加更复杂的代码逻辑或者业务的增长导致处理量上升的时候会使Spark因计算资源不足,这时候如果没有做流量控制则Spark任务会因内存承受不了而失败,如果做了流量控制则Kafka的lag会有堆积,这时候一般就需要增加更多的executor来处理,但是增加多少合适一般不太好判断,于是要反复地修改配置重新发布来找到一个合理的配置。
我们在Marathon上使用Logstash的时候也有类似的问题,当由于接入一个比较大的日志导致流量突然增加使得Logstash处理不了时,Kafka的Lag产生堆积,这时我们只需直接上Marathon的界面上点Scale然后填入更大的实例数字就能启动了一些Logstash实例自动平衡地去处理了。当发现某个结点是慢结点不干活的时候,只需要在Marathon上将对应的任务Kill掉就会自动再发一个任务替补他的位置,那么Logstash既然都可以做到为什么Spark不可以?因此我们决定在Spark2.0版本的时候来实现这个功能,同时我们也会改进其它的一些问题,另外Spark2.0是一个比较大的版本升级,配置与之前的1.6.1不同,不能做到直接全部重发一遍任务来做到全部升级。
(图1)使用Logstash的管理架构Mesos-dispacher架构与问题在这里我们首先介绍一些Mesos的一些相关概念,Mesos的Framework是资源分配与调度的发起者,Spark自带了一个spark-mesos-dispacher的Framework用来管理Spark的资源调度。而Marathon也是一个Framework他的本质和mesos-dispacher或sparkschedular相同。
(图2)Mesos-dispacher架构在图2在这个架构中,你首先得向mesos注册一个mesos-dispacher的Framework,然后,通过spark-sumbit脚本来向mesos-dispacher发布任务,mesos-dispacher接到任务以后开始调度他负责发一个SparkDriver,然后driver在mesos模式下,他会再次向mesos注册这个任务的Framework也就是我们看到的SparkUI,也可以理解为他自己也是个调度器,然后这个Framework根据配置来向Mesos申请资源来发一些SparkExecutor。
(图3)Mesos-dispacher功能截图从图3可以看出,mesos-dispacher只提供了下功能:
他只提供了一个配置查看的界面,可以看到资源分配的信息,点进去以后可以看到SparkConf的一些参数,但是这个我们在业务线发布的时候已经拿到了这些配置,在这里只能确认下Driver是否配置正确,并且在SparkUI上也能看到。
他自带一个Driver队列,他会按顺序依次发布,当资源不足时会在队列里等待。
他自带一个Driver的HA功能,但是当你提交Driver代码有问题,他会不断地反复重发,比较难杀掉,但也是能杀掉的,并且没有次数限制。所以我们一般也不开放这个功能。
所以mesos-dispacher并不是一个完备的Framework,在我们使用的过程中发现了存在以下的问题:
在我们发布Spark的时候需要向mesos-dispacher提供一个SPARK_EXECUTOR_URI的配置来提供SPARK运行环境的地址,一开始我们是使用