我们都知道sparkstreaming实时流,项目一旦运行起来,就不会轻易的停止的,我们一般使用命令yarn application -kill applicationID 直接的进行关闭。一般的sparkstreaming项目消费kaf卡里面的实时数据的,如果我们没有做好kafka的offset的处理的话,很可能会导致处理数据的丢失。这在生产中是不被允许的事情。
sprakstreaming优雅停止服务的三种方式
1.spark1.3之前的方式
使用Runtime.getRuntime().addShutdownHook()注册关闭钩子的方法,在jvm要退出之前调用spark的stop方法,进行优雅关闭。 java代码:
Runtime.getRuntime().assShutdownHook(new Thread(){
override def run(){
ssc.stop(true,true);
}
})
这样能保证进程在被kill之前,在driver结束之前,ssc.stop会被调用,从而保证数据被处理掉。
2.spark1.4之后的版本
1.4之后,spark提供了一个新的关于优雅关闭的配置,只需要设置配置如下:
sparkConf.set("spark.streaming.stopGracefullyOnShutdown","true");
使用这种方式,不需要开发者调用ssc.stop()来停止程序。需要开发人员发送sigterm信号给Driver。步骤如下: 1.到yarn的web界面,跳到spark的UI界面,找到excetor界面,看driver运行在那个container里面,container,在那个nodemanger所在的主机上面。 2.使用 kill -15 或者是kill -SIGTERM 给driver所在的进程号,或者是封装一条命令
sudo ss -tanlp | grep 5555 |awk '{print $6}'|awk -F, '{print $2}' | sudo xargs kill -15
这种方法,使用起来还是比较麻烦的,因为Driver每次在集群中启动的位置肯定是不固定的,每次都去找有点不太现实。 下面介绍第二种方法
hdfs做消息通知
这个方法的根本也是调用sparkcontext的stop方法,但是他通知进程调用的方式是比较好的。 在驱动程序中加上一段代码,这段代码的作用是每个一定的时间去扫描hdfs上面的一个文件,这里可以定位发现文件关闭sparkstreaming程序或者是文件被删除了关闭spark,都是可以的。然后调用sparkcontext的stop方法,自己优雅的停止服务。其实这里的hdfs只是一个消息通知的作用,换成redis,hbase,mysql都是可以的。使用这种方式停止服务就是比较简单的了,使用hdfs命令对文件进行删除和创建,通知程序关闭就行了。 下面对这种方式进行代码的演示
val ssc = new StreamingContext(sc, Seconds(1))
val lines = ssc.socketTextStream("master", 9999)
val words = lines.flatMap(_.split(" "))
val pairs = words.map(word => (word, 1))
val wordCounts = pairs.reduceByKey(_ + _)
wordCounts.print()
ssc.start()
Shutdown.stop("/spark",()->ssc.stop(true,true));
ssc.awaitTermination()
----------------------------------------------------------------------------------4
#下面是java代码
public class ShutDown{
public void stop(String path,Runable task){
new Thread(() -> {
String cmd = "hdfs dfs -ls " + path;
while (true) {
try {
Thread.sleep(5000L);
Process exec = Runtime.getRuntime().exec(path);
InputStream inputStream = exec.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8");
String s = bufferedReader.readLine();
if(StringUtils.isNotBlank(s) && s.contains(path)){
task.run();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
------------------------------------------------------------------------------
关闭spark程序的命令可以写一个shell的脚本,这里就简单的写一下
vim stop-spark.sh
#!/bin/bash
hdfs dfs -mkdir /spark
这里注意,启动的时候,最好也写一个对应的启动项目的脚本,把hdfs里面的文件夹给删掉
参考:www.jianshu.com/p/e92bd93fa… www.jianshu.com/p/b11943c94…