前段时间看到了外国朋友写的一篇文章,觉得还不错,于是就把他翻译一下,供大家参考和学习。
如果没看过前两篇文章(第一篇、第二篇),建议先去看一下哈,这里是接着上两篇文章来写的哈~
Grafana
当你为 Spark 应用程序配置第一个 Grafana 仪表板时,首先出现的问题是:
How to configure Graphite query when metrics for every Spark application run are reported under its own application id?(注:不好意思,这句不知怎么翻译)
如果你足够幸运并且勇于使用Spark 2.1,请将应用程序的 metric 固定为静态的应用程序名称:
--conf spark.metrics.namespace=my_application_name
对于2.1以上的Spark版本,需要使用Graphite内置函数的一些用法。
Driver metrics 使用通配符 .*(application_[0-9]+).*
和 aliasSub
Graphite 的函数将 “application id” 显示为图例:
aliasSub(stats.analytics.$job_name.*.prod.$dc.*.driver.jvm.heap.used, ".*(application_[0-9]+).*", "heap: \1")
对于 executor metrics,再次使用.*(application_[0-9]+).*
和 aliasSub
函数来对所有 Spark executor 的 metric 值进行求和,最后使用aliasSub
函数将“application id”作为图例表示:
aliasSub(groupByNode(stats.analytics.$job_name.*.prod.$dc.*.[0-9]*.jvm.heap.used, 6, "sumSeries"), "(.*)", "heap: \1")
最后,Spark Job 的 Grafana 仪表板大致如下所示:
如果经常重新启动 Spark 应用程序,则应该从 Graphite 中删除旧的已完成运行的 metrics。 由于 Graphite 没有合并不活动的 metrics,因此旧 metrics 会减慢Graphite 本身和 Grafana 查询的速度。
优雅地停止
最后一个难题是如何以一种优雅的方式停止在 Yarn 上部署的 SparkStreaming 程序。停止(或杀死)YARN 应用程序的标准方法是使用yarn application -kill [applicationId]
命令。这个命令能停止我们的程序,但是程序有可能在小批处理的过程中。因此,如果 job 读取 Kafka 的数据,将处理结果保存在 HDFS 上,并最终提交 Kafka 偏移量,那么当作业在提交偏移量之前停止时,应该将该批次的数据保存在 HDFS中(注:receiver的方式)。
解决正常停止问题的第一个尝试是 在 shutdown hook(关闭钩子)中调用 SparkStreaming context 的停止方法。
sys.addShutdownHook {
streamingContext.stop(stopSparkContext = true, stopGracefully = true)
}
令人失望的是,shutdown hook(关闭挂钩)被调用得太晚以至于无法完成已经开始的一小批的处理,并且Spark应用程序几乎立即被杀死。 而且,根本不能保证关闭钩子会被JVM调用。
在编写本博文时,优雅地关闭 YARN 上的 Spark Streaming 应用程序的唯一确认方式是 以某种方式通知关于打算停止的 application,然后以编程的方式停止 streaming context(但不是关闭挂接的方式)。 如果通知的 application 在定义的时间后仍然没有停止,那么可以调用命令yarn application -kill
作为最后的手段。
应用程序可以在 HDFS 上使用标记文件(最简单的方法),或者使用在 Driver上公开的简单的socket/http端点(复杂的方式)通知 application。
因为我喜欢KISS原则,所以在下面就是使用标记文件来启动/停止 Spark Streaming 应用程序的 shell 脚本伪代码:
start() {
hdfs dfs -touchz /path/to/marker/my_job_unique_name
spark-submit ...
}
stop() {
hdfs dfs -rm /path/to/marker/my_job_unique_name
force_kill=true
application_id=$(yarn application -list | grep -oe "application_[0-9]*_[0-9]*"`)
for i in `seq 1 10`; do
application_status=$(yarn application -status ${application_id} | grep "State : \(RUNNING\|ACCEPTED\)")
if [ -n "$application_status" ]; then
sleep 60s
else
force_kill=false
break
fi
done
$force_kill && yarn application -kill ${application_id}
}
在 Spark Streaming 应用程序中,后台线程应监视标记文件,并在文件消失时调用 context 的 stop 方法
streamingContext.stop(stopSparkContext = true, stopGracefully = true)
总结
如你所见,部署在 YARN 上的关键任务 Spark Streaming 应用程序的配置非常复杂。 这是由一些非常聪明的开发者经过漫长而乏味的迭代过程总结出来的。 但最后,长期运行的 Spark Streaming 应用程序非常稳定地部署在高度利用的 YARN 群集上。
注:本文翻译自:http://mkuthan.github.io/blog/2016/09/30/spark-streaming-on-yarn/