sparkstreaming优雅停止服务

780 阅读3分钟

我们都知道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…