我有一个Spark流媒体应用程序,该应用程序基本上从Kafka那里收到触发消息,它会启动批处理,这可能要花费2个小时。
有些事件会导致某些作业无限期地挂起,并且在通常的时间内没有完成,并且目前无法在不手动检查Spark UI的情况下找出作业状态。我希望有一种方法可以解决当前正在运行的Spark作业是否挂起的问题。因此,基本上,如果挂起超过30分钟,我想通知用户以便他们采取措施。我有什么选择?
我看到我可以使用驱动程序和执行程序中的指标。如果我选择最重要的记录,那将是最后收到的批记录。当StreamingMetrics.streaming.lastReceivedBatch_records == 0时,它可能意味着Spark流作业已停止或失败。
但是在我的情况下,我将仅收到1个流触发事件,然后它将启动处理过程,这可能需要2个小时,因此我将无法依赖收到的记录。
有更好的方法吗? TIA
答案 0 :(得分:1)
YARN提供了REST API来检查应用程序状态和群集资源利用状态。
通过API调用,它将提供正在运行的应用程序及其启动时间和其他详细信息的列表。您可以有一个简单的REST客户端,它每30分钟左右触发一次,然后检查作业是否运行了2个小时以上,然后发送简单的邮件警报。
以下是API文档:
答案 1 :(得分:0)
大约一年前,我遇到过类似的情况,这就是我所做的-
Kafka
收到消息后,spark streaming
作业将接收事件并开始处理。
Spark streaming
作业向email
发送警报Support group
,提示“收到事件并触发转换STARTED
”。 Start timestamp
已存储。
完成火花处理/转换后-向支持小组发送警报email
,提示“火花转换ENDED
成功”。 End timestamp
已存储。
以上两个步骤将帮助支持小组跟踪启动后是否未收到火花处理成功电子邮件,他们可以通过查看火花UI来调查作业失败或延迟处理(可能是由于资源长时间无法使用而导致作业挂起)时间)
最后-将事件ID或详细信息以及开始和结束时间戳记存储在HDFS
文件中。并将此文件保存到某个配置单元HDFS
指向的log_table
路径中。这对于将来参考火花代码在这段时间内的性能很有帮助,如果需要,可以fine tuned
。
希望这会有所帮助。
答案 2 :(得分:0)
我目前正在与Google Spark Operator一起使用Kubernetes。 [1]
使用Spark 2.4.3时,我的某些流作业挂起:很少的任务失败,因此当前的批处理作业永远不会进行。
我使用StreamingProgressListener
设置了超时时间,以便线程在很长时间内没有新批处理提交时发出信号。然后将信号转发到Pushover客户端,该客户端将通知发送到Android设备。然后调用System.exit(1)
。 Spark操作员最终将重新启动作业。
[1] https://github.com/GoogleCloudPlatform/spark-on-k8s-operator
答案 3 :(得分:0)
一种方法是监视启动的火花作业的输出。通常,例如,
答案 4 :(得分:0)
也许是一个简单的解决方案。
在处理开始时-启动一个等待线程。
val TWO_HOURS = 2 * 60 * 60 * 1000
val t = new Thread(new Runnable {
override def run(): Unit = {
try {
Thread.sleep(TWO_HOURS)
// send an email that job didn't end
} catch {
case _: Exception => _
}
}
})
在可以说批处理结束的地方
t.interrupt()
如果处理在2小时内完成-服务线程中断并且不发送电子邮件。如果未完成处理-将发送电子邮件。
答案 5 :(得分:0)
利用 TaskContext
这提供了任务的上下文信息,并支持为任务完成/失败添加侦听器(请参阅addTaskCompletionListener)。
还有更多详细信息,例如任务“ attemptNumber”或“ taskMetrics”。
您的应用程序可以在运行时使用此信息来确定它们是否为“挂起”(取决于问题)
有关“挂起”的更多信息将有助于提供更具体的解决方案。
答案 6 :(得分:0)
让我引起您对Streaming Query侦听器的注意。这些都是非常惊人的轻量级功能,可以监视您的流式查询进度。
在具有多个查询的应用程序中,您可以找出哪些查询因某些异常而滞后或已停止。
请找到以下示例代码以了解其实现。我希望您可以使用它并将其转换为更适合您的需求。谢谢!
spark.streams.addListener(new StreamingQueryListener() {
override def onQueryStarted(event: QueryStartedEvent) {
//logger message to show that the query has started
}
override def onQueryProgress(event: QueryProgressEvent) {
synchronized {
if(event.progress.name.equalsIgnoreCase("QueryName"))
{
recordsReadCount = recordsReadCount + event.progress.numInputRows
//Logger messages to show continuous progress
}
}
}
override def onQueryTerminated(event: QueryTerminatedEvent) {
synchronized {
//logger message to show the reason of termination.
}
}
})