实验前后效果对比:

之前:执行13个节点,耗时16分钟

之后:同样13个节点,耗时3分钟

具体逻辑请参照代码及注释。

 import java.util.concurrent.{ExecutorService, Executors, TimeUnit}

 import akka.actor.{ActorSystem, Props}
import com.alibaba.fastjson.JSONObject
import xxx.listener.AddJobToQueueActor
import xxx.listener.bean.{AppStatusMessage, SparkContextStatusMessage}
import xxx.listener.utils.JSONUtil
import xxx.listener.utils.JmsUtils._
import xxx.main.SparkJob
import xxx.main.utils.JsonUtils
import com.typesafe.config.ConfigFactory
import org.apache.commons.lang.StringUtils
import org.apache.spark.sql.hive.HiveContext
import org.apache.spark.{Logging, SparkConf, SparkContext} import scala.collection.mutable.Queue /**
* Created by zpc on 2016/9/1.
* JobServer实现模板。
* 修正前:各个任务节点独立提交到spark平台,其中启动sparkContext和hiveContext会占用大量时间,大约40多秒。
* 修改后:将统一用户,占用资源相同的节点利用JMS发送消息提交到同一个SparkContext上,默认设置为3个节点任务并行。
* 实现:1.提交到queue中的msg为任务包含任务中型的子类及参数信息,接收到的任务不存在依赖关系,依赖的处理在消息发送端控制。
* 前置任务执行结束,再发送下一节点任务。
* 2.第一次提交时,任务的参数在args中获取。启动之后,启动jms的lister监听,通过actor将接收到的任务信息加入队列。
* 3.通过反射调用SparkJob的各个子类(真正执行节点逻辑的类),SparkContext的默认timeout时间为30mins。
* 4.节点执行结束,发送节点成功消息到web端,节点失败,发送错误日志及错误消息。
* 程序退出,通过shutdownhook,发送sc关闭消息到web端。
* 程序被关闭,如kill时,将等待队列及正在执行集合中的任务,发送失败消息到web端。
*
*
*/
object ExecuteJobServer extends Logging { //等待执行的job所在的queue
val jobWaitingQueue = new Queue[String]
//当前正在执行的任务的集合
val jobRunningSet = new scala.collection.mutable.HashSet[JSONObject]
val timeout_mins = 30
//最后运行任务时间
var lastRunTime = System.currentTimeMillis() //spark context 对应的 applicationId, user, expId, resource
var appId : String = ""
var user: String = ""
var expId: Long = 0
var resource: String = ""
//正在执行的job JSON
var jobJson : JSONObject = null def main(args: Array[String]): Unit = { //进程杀死时,将正在执行或未执行的任务,发送失败消息到web端。
Runtime.getRuntime().addShutdownHook(new HookMessage())
//接收到的任务,可以同时提交时,线程数可以多设置,暂定为3
val threadPool: ExecutorService = Executors.newFixedThreadPool(3)
val sc = initSparkContext()
val hiveContext = new HiveContext(sc) val list = JsonUtils.parseArray(args(0))
val it = list.iterator
while (it.hasNext) {
val jobStr = it.next().toString
if(expId == 0){
val json = JSONUtil.toJSONString(jobStr)
val param = json.getJSONObject("params")
appId = sc.applicationId
user = param.getString("user")
expId = param.getLongValue("expId")
var driver_memory = ""
var num_executors = "spark.executor.instances"
var executor_memory = ""
sc.getConf.getAll.map( x => {
if(x._1 != null && "spark.executor.instances".equals(x._1)) {
num_executors = x._2
}
else if(x._1 != null && "spark.executor.memory".equals(x._1)){
executor_memory = x._2.substring(0, x._2.length - 1)
}else if(x._1 != null && "spark.driver.memory".equals(x._1)){
driver_memory = x._2.substring(0, x._2.length - 1)
}
}) resource = driver_memory + num_executors + executor_memory;
logInfo("resource is : " +resource)
// resource = param.getString("driver-memory") + param.getString("num-executors") + param.getString("executor-memory")
}
jobWaitingQueue.enqueue(jobStr)
} /** 1.启动listener监听appId,接收queue中发送过来的JobMsg消息2.通过Queue发送消息通知web端,sc启动 **/
val system = ActorSystem("mlp", ConfigFactory.load())
val actor = system.actorOf(Props(new AddJobToQueueActor(appId, jobWaitingQueue)))
createTopicListenerOfContextJobMsg("contextJobMsgListener", actor)
informSparkContextStatus(true) while (jobWaitingQueue.size > 0 || !checkTimeOut) {
while (jobWaitingQueue.size > 0) {
lastRunTime = System.currentTimeMillis()
val jobStr = jobWaitingQueue.dequeue()//.replace("\\", "")
logInfo("***** ExecuteJobServer jobStr ***** jobStr: " + jobStr)
val json = JSONUtil.toJSONString(jobStr)
jobRunningSet.add(json)
threadPool.execute(new ThreadSparkJob(json, hiveContext, sc))
jobJson = json
}
Thread.sleep(1000)
} /**
* jobWaittingQueue队列不再接收消息
*
*/
threadPool.shutdown()
var loop = true
do {
//等待所有任务完成
loop = !threadPool.awaitTermination(2, TimeUnit.SECONDS); //阻塞,直到线程池里所有任务结束
} while (loop);
} def checkTimeOut(): Boolean = {
val nowTime = System.currentTimeMillis()
if (jobRunningSet.isEmpty && (nowTime - lastRunTime) / (1000 * 60) > timeout_mins) {
return true
} else {
return false
}
} class ThreadSparkJob(json: JSONObject, hiveContext: HiveContext, ctx: SparkContext) extends Runnable {
override def run() { try{
val classStr = json.get("class").toString
val argsStr = json.get("params").toString
val obj: SparkJob = Class.forName(classStr).getMethod("self").invoke(null).asInstanceOf[SparkJob]
// val obj: SparkJob = Class.forName(classStr).newInstance().asInstanceOf[SparkJob]
obj.jobServer = true
obj.failed = false
obj.setContext(ctx)
obj.setHiveContext(hiveContext)
obj.main(Array(argsStr))
// InformJobSuccess(json)
logInfo("***** jobRunningSet remove job json***** json: " + json.toJSONString )
jobRunningSet.remove(json)
lastRunTime = System.currentTimeMillis()
}catch {
case oom: OutOfMemoryError => {
informJobFailure(oom.toString, json)
jobRunningSet.remove(json)
logInfo("***** SparkContext go to stop, reaseon: " + oom.getMessage )
hiveContext.sparkContext.stop()
//异常时,sc停止,driver程序停止
System.exit(1)
}
case ex: Exception => {
informJobFailure(ex.toString, json)
jobRunningSet.remove(json)
if(ex.toString.contains("stopped SparkContext")){
logInfo("***** SparkContext go to stop, reaseon: " + ex.getMessage )
hiveContext.sparkContext.stop()
//异常时,sc停止,driver程序停止
System.exit(1)
}
}
}
}
def informJobFailure(errMsg: String, json: JSONObject) = {
if(json != null) {
val params = json.getJSONObject("params")
val user = StringUtils.trimToEmpty(params.getString("user"))
val expId = params.getLongValue("expId")
val nodeId = params.getLongValue("nodeId")
val message = new AppStatusMessage(user, expId, nodeId, "FAILURE", errMsg)
logInfo("***** send informJobFailure message*****: expId: " + expId + "nodeId: " + nodeId)
jobStatusTemplate send message
}
}
} def initSparkContext(): SparkContext = {
val conf = new SparkConf().setAppName("cbt-mlaas")
new SparkContext(conf)
} class HookMessage extends Thread {
override def run() {
var shouldInformStop = false
informSparkContextStatus(false)
while (jobWaitingQueue.size > 0) {
val jobStr = jobWaitingQueue.dequeue()//.replace("\\", "")
val json = JSONUtil.toJSONString(jobStr)
informJobFailureInHook("SparkContext stopped, inform waiting job failed!", json)
shouldInformStop = true
}
jobRunningSet.map(json => {
informJobFailureInHook("SparkContext stopped, inform running job failed!", json);
shouldInformStop = true
})
if (shouldInformStop) {
informExpStop("SparkContext stopped, inform exp failed!", jobJson)
}
}
def informJobFailureInHook(errMsg: String, json: JSONObject) = {
if(json != null) {
val params = json.getJSONObject("params")
val user = StringUtils.trimToEmpty(params.getString("user"))
val expId = params.getLongValue("expId")
val nodeId = params.getLongValue("nodeId")
val message = new AppStatusMessage(user, expId, nodeId, "FAILURE", errMsg)
logInfo("***** send informJobFailure message*****: expId: " + expId + "nodeId: " + nodeId)
jobStatusTemplate send message
}
}
def informExpStop(errMsg: String, json: JSONObject) = {
if(json != null) {
val params = json.getJSONObject("params")
val user = StringUtils.trimToEmpty(params.getString("user"))
val expId = params.getLongValue("expId")
val nodeId = params.getLongValue("nodeId")
val message = new AppStatusMessage(user, expId, nodeId, "STOP", errMsg)
logInfo("***** send informExpStop message*****: expId: " + expId + "nodeId: " + nodeId)
jobStatusTemplate send message
}
}
} def informSparkContextStatus(start : Boolean) = {
val msg = new SparkContextStatusMessage(appId, start, user, expId, resource)
logInfo("***** send sparkContext start message*****: appId: " + appId + "start: " + start)
sparkContextStatusTemplate send msg
} }

通过模板类简单实现Spark的JobServer的更多相关文章

  1. [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)

    首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下:  C++ Code  1 2   template < class _Ty, cl ...

  2. [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)

    首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下:  C++ Code  1 2   template <  class _Ty,  ...

  3. 实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)

    首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下:  C++ Code  1 2   template < class _Ty, cl ...

  4. C++入门经典-例9.3-类模板,简单类模板

    1:使用template关键字不但可以定义函数模板,而且可以定义类模板.类模板代表一族类,它是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的参数或返回值可以取任意数据类型.类 ...

  5. 类的编写模板之简单Java类

    简单Java类是初学java时的一个重要的类模型,一般由属性和getter.setter方法组成,该类不涉及复杂的逻辑运算,仅仅是作为数据的储存,同时该类一般都有明确的实物类型.如:定义一个雇员的类, ...

  6. c++模板类

    c++模板类 理解编译器的编译模板过程 如何组织编写模板程序 前言常遇到询问使用模板到底是否容易的问题,我的回答是:“模板的使用是容易的,但组织编写却不容易”.看看我们几乎每天都能遇到的模板类吧,如S ...

  7. C++模板类的使用

    1.定义模板类 通过类似于下面的语法可以定义一个模板类: template<typename T> class Job : public virtual RefBase { public: ...

  8. C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)

    1.  主版本模板类 首先我们来看一段初学者都能看懂,应用了模板的程序: 1 #include <iostream> 2 using namespace std; 3 4 template ...

  9. C++中的链表节点用模板类和用普通类来实现的区别

    C++中的链表节点通常情况下类型都是一致的.因此我们可以用模板来实现. #include <iostream> using namespace std; template<typen ...

随机推荐

  1. C# winform关于DataGridView的一些操作

    设置字段名 设置字段值 设定单元格表示 Error图标 设定当前单元格 取得当前单元格内容 取得当前单元格的列 Index 取得当前单元格的行 Index 向下一行 向上一行 取消 DataGridV ...

  2. oracle,wamp,FZ突然出现问题,求解决方案(未解决,最终系统还原)

    -----背景------- 系统:win7  64位oracle 11g(11.1)每天都用oracle.用toad for oracle .电脑固定IP.未更改任何配置信息.用了几个月,突然出现了 ...

  3. centos 关闭触摸板,触摸板点击

    yum install xorg-x11-apps xinput –list 由图可以看出俺的本本触摸板ID为14,于是可以通过以下命令开启与关闭它: 禁止touchpad:xinput set-in ...

  4. Erlang 开发者的福音:IntelliJ IDEA 的 Erlang 插件

    IntelliJ IDEA 的 Erlang 插件,主要特性: 智能编辑器:  Erlang 代码补全.语法和错误高亮.代码检查 代码导航:项目和文件结构视图.在文件.模型.函数和用例之间快速跳转 工 ...

  5. 大话F#和C#:是否会重蹈C#失败的覆辙?

    F#.net 出来有些年头儿了,将从 VS 2010 起在 .net framework 平台上以“一等公民”身份粉墨登场的它,将会给计算机科技与软件工业带来哪些悲喜剧呢? F# 将扮演一个什么角色? ...

  6. 常用PHP运行环境一键安装包

    PHP的程序很火,像博客:Wordpress.论坛:Discuz!.SNS:UCenter Home.CMS:DedeCMS等等都是比较流行的PHP程序,大家都在使用PHP类的程序,但对于很多初学者来 ...

  7. Bootstrap优秀网站:乐窝网

    Bootstrap优秀网站:乐窝网 调用谷歌在线地图的API和Bootstrap工具包实现了租房和出租的一个平台. 佩服之极,09年跟一个哥们聊天时,他就提议过这方面的应用,终于看到有人实现了,祝贺. ...

  8. 【转】oracle 针对中文字段进行排序

    1)按笔画排序 select * from Table order by nlssort(columnName,'NLS_SORT=SCHINESE_STROKE_M') 2)按部首排序 select ...

  9. org.springframework.web.servlet.view.InternalResourceViewResolver

    http://blog.csdn.net/superdog007/article/details/28857495 我们在controller里面经常这样return一个ModelAndView: r ...

  10. joda jar日期处理类的学习

    转载:http://www.open-open.com/lib/view/open1348032952724.html 任何企业应用程序都需要处理时间问题.应用程序需要知道当前的时间点和下一个时间点, ...