Spark2.2(三十九):如何根据appName监控spark任务,当任务不存在则启动(任务存在当超过多久没有活动状态则kill,等待下次启动)
业务需求
实现一个根据spark任务的appName来监控任务是否存在,及任务是否卡死的监控。
1)给定一个appName,根据appName从yarn application -list中验证任务是否存在,不存在则调用spark-submit.sh脚本来启动任务;
2)如果任务存在yarn application -list中,则读取‘监控文件(监控文件内容包括:appId,最新活动时间)’,从监控文件中读取出最后活动的日期,计算当前日期与app的最后活动日期相差时间为X,如果X大于30minutes(认为任务处于假死状态[再发布环境发现有的任务DAG抛出OOM,导致app的executor和driver依然存在,当时不执行任务调度,程序卡死。具体错误详情请参考《https://issues.apache.org/jira/browse/SPARK-26452》]),则执行yarn application -kill appId(杀掉任务),等待下次监控脚本执行时重启任务。
监控实现
脚本
#/bin/sh
#LANG=zh_CN.utf8
#export LANG
export SPARK_KAFKA_VERSION=0.10
export LANG=zh_CN.UTF-
# export env variable
if [ -f ~/.bash_profile ];
then
source ~/.bash_profile
fi
source /etc/profile myAppName='myBatchTopic' #这里指定需要监控的spark任务的appName,注意:这名字重复了会导致监控失败。
apps='' for app in `yarn application -list`
do
apps=${app},$apps
done
apps=${apps%?} if [[ $apps =~ $myAppName ]];
then
echo "appName($myAppName) exists in yarn application list"
#)运行 hadop fs -cat /目录/appName,读取其中最后更新日期;(如果文件不存在,则跳过等待文件生成。)
monitorInfo=$(hadoop fs -cat /user/dx/streaming/monitor/${myAppName})
LD_IFS="$IFS"
IFS=","
array=($monitorInfo)
IFS="$OLD_IFS"
appId=${array[]}
monitorLastDate=${array[]}
echo "loading mintor information 'appId:$appId,monitorLastUpdateDate:$monitorLastDate'" current_date=$(date "+%Y-%m-%d %H:%M:%S")
echo "loading current date '$current_date'" #)与当前日期对比:
# 如果距离当前日期相差小于30min,则不做处理;
# 如果大于30min则kill job,根据上边yarn application -list中能获取对应的appId,运行yarn application -kill appId
t1=`date -d "$current_date" +%s`
t2=`date -d "$monitorLastDate" +%s`
diff_minute=$(($(($t1-$t2))/))
echo "current date($current_date) over than monitorLastDate($monitorLastDate) $diff_minute minutes"
if [ $diff_minute -gt ];
then
echo 'over then 30 minutes'
$(yarn application -kill ${appId})
echo "kill application ${appId}"
else
echo 'less than 30 minutes'
fi
else
echo "appName($myAppName) not exists in yarn application list"
#./submit_x1_x2.sh abc TestRestartDriver #这里指定需要启动的脚本来启动相关任务
$(nohup ./submit_checkpoint2.sh >> ./output.log >& &)
fi
监控脚本业务流程图:

监控文件生成
我这里程序是spark structured streaming,因此可以注册sparkSesssion的streams()的query的监听事件
sparkSession.streams().addListener(new GlobalStreamingQueryListener(sparkSession。。。))
在监听事件中实现如下:
public class GlobalStreamingQueryListener extends StreamingQueryListener {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(GlobalStreamingQueryListener.class);
private static final String monitorBaseDir = "/user/dx/streaming/monitor/";
private SparkSession sparkSession = null;
private LongAccumulator triggerAccumulator = null;
public GlobalStreamingQueryListener(SparkSession sparkSession, LongAccumulator triggerAccumulator) {
this.sparkSession = sparkSession;
this.triggerAccumulator = triggerAccumulator;
}
@Override
public void onQueryStarted(QueryStartedEvent queryStarted) {
System.out.println("Query started: " + queryStarted.id());
}
@Override
public void onQueryTerminated(QueryTerminatedEvent queryTerminated) {
System.out.println("Query terminated: " + queryTerminated.id());
}
@Override
public void onQueryProgress(QueryProgressEvent queryProgress) {
System.out.println("Query made progress: " + queryProgress.progress());
// sparkSession.sql("select * from " +
// queryProgress.progress().name()).show();
triggerAccumulator.add(1);
System.out.println("Trigger accumulator value: " + triggerAccumulator.value());
logger.info("minitor start .... ");
try {
if (HDFSUtility.createDir(monitorBaseDir)) {
logger.info("Create monitor base dir(" + monitorBaseDir + ") success");
} else {
logger.info("Create monitor base dir(" + monitorBaseDir + ") fail");
}
} catch (IOException e) {
logger.error("An error was thrown while create monitor base dir(" + monitorBaseDir + ")");
e.printStackTrace();
}
// spark.app.id application_1543820999543_0193
String appId = this.sparkSession.conf().get("spark.app.id");
// spark.app.name myBatchTopic
String appName = this.sparkSession.conf().get("spark.app.name");
String mintorFilePath = (monitorBaseDir.endsWith(File.separator) ? monitorBaseDir : monitorBaseDir + File.separator) + appName;
logger.info("The application's id is " + appId);
logger.info("The application's name is " + appName);
logger.warn("If the appName is not unique,it will result in a monitor error");
try {
HDFSUtility.overwriter(mintorFilePath, appId + "," + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
} catch (IOException e) {
logger.error("An error was thrown while write info to monitor file(" + mintorFilePath + ")");
e.printStackTrace();
}
logger.info("minitor stop .... ");
}
}
HDFSUtility.java中方法如下:
public class HDFSUtility {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HDFSUtility.class);
/**
* 当目录不存在时,创建目录。
*
* @param dirPath
* 目标目录
* @return true-創建成功;false-失敗。
* @throws IOException
* */
public static boolean createDir(String dirPath) throws IOException {
FileSystem fs = null;
Path dir = new Path(dirPath);
boolean success = false;
try {
fs = FileSystem.get(new Configuration());
if (!fs.exists(dir)) {
success = fs.mkdirs(dir);
} else {
success = true;
}
} catch (IOException e) {
logger.error("create dir (" + dirPath + ") fail:", e);
throw e;
} finally {
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return success;
}
/**
* 覆盖文件写入信息
*
* @param filePath
* 目标文件路径
* @param content
* 被写入内容
* @throws IOException
* */
public static void overwriter(String filePath, String content) throws IOException {
FileSystem fs = null;
// 在指定路径创建FSDataOutputStream。默认情况下会覆盖文件。
FSDataOutputStream outputStream = null;
Path file = new Path(filePath);
try {
fs = FileSystem.get(new Configuration());
if (fs.exists(file)) {
System.out.println("File exists(" + filePath + ")");
}
outputStream = fs.create(file);
outputStream.write(content.getBytes());
} catch (IOException e) {
logger.error("write into file(" + filePath + ") fail:", e);
throw e;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Spark2.2(三十九):如何根据appName监控spark任务,当任务不存在则启动(任务存在当超过多久没有活动状态则kill,等待下次启动)的更多相关文章
- Spark2.3(三十六):根据appName验证某个app是否在运行
具体脚本 #/bin/sh #LANG=zh_CN.utf8 #export LANG export SPARK_KAFKA_VERSION=0.10 export LANG=zh_CN.UTF- # ...
- NeHe OpenGL教程 第三十九课:物理模拟
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- Java进阶(三十九)Java集合类的排序,查找,替换操作
Java进阶(三十九)Java集合类的排序,查找,替换操作 前言 在Java方向校招过程中,经常会遇到将输入转换为数组的情况,而我们通常使用ArrayList来表示动态数组.获取到ArrayList对 ...
- Gradle 1.12用户指南翻译——第三十九章. IDEA 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- SQL注入之Sqli-labs系列第三十八关、第三十九关,第四十关(堆叠注入)
0x1 堆叠注入讲解 (1)前言 国内有的称为堆查询注入,也有称之为堆叠注入.个人认为称之为堆叠注入更为准确.堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新 的查询或者终止查询,可以达到修改数据 ...
- 第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式
第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式 我们自定义一个main.py来作为启动文件 main.py #!/usr/bin/en ...
- centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/index.php <<EOF重定向 shell的变量和函数命名不能有横杠 平台可以用arch命令,获取是i686还是x86_64 curl 下载 第三十九节课
centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/ind ...
- “全栈2019”Java第三十九章:构造函数、构造方法、构造器
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形
原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...
随机推荐
- Codeforces round FF
Problem A:水题,直接gan #include<bits/stdc++.h> using namespace std; ; int vis[N]; int main() { int ...
- Linux下C语言的文件操作
代码: #include <stdio.h> #include <string.h> #include <fcntl.h> /*************基本的函数A ...
- js判断上传图片文件大小,尺寸,格式
/** * 文件宽高 * @param eventId id * @param w 宽度 * @param h 高度 * @param callback 回调函数这里判断图片像素的方法是异步的,所以需 ...
- 生日蛋糕 POJ - 1190 (搜索+剪枝)
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱.当 ...
- Running Median POJ - 3784 (对顶堆/优先队列 | 链表)
For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After ...
- POJ 2418 Hardwood Species 【Trie树】
<题目链接> 题目大意: 给你一堆字符串,让你按字典序输出他们出现的频率. 解题分析: 首先,这是Trie数词频统计的题目,以Trie树的边储存字母,节点存储以该节点结尾的链所代表的字符串 ...
- HDU 1257 最少拦截系统 【贪心】
<题目链接> 题目大意: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度 ...
- 大数据小白系列——HDFS(4)
这里是大数据小白系列,这是本系列的第四篇,来看一个真实世界Hadoop集群的规模,以及我们为什么需要Hadoop Federation. 首先,我们先要来个直观的印象,这是你以为的Hadoop集群: ...
- python 数据结构之归并排序
def merger_sort(alist): if len(alist) <= 1 : return alist num=int(len(alist)/2) left=merger_sort( ...
- BZOJ-8-2115: [Wc2011] Xor
https://www.lydsy.com/JudgeOnline/problem.php?id=2115 题意 : 给出一个连通无向图,求从1到n异或和最小的路径. 思路 :随意找一条简单路径 1- ...