暴力停掉sparkstreaming是有可能出现问题的,比如你的数据源是kafka,已经加载了一批数据到sparkstreaming中正在处理,如果中途停掉,这个批次的数据很有可能没有处理完,就被强制stop了,下次启动时候会重复消费或者部分数据丢失。
如何解决呢?
一、如果只是本地并且一次性的测试,只需要在SparkConf里面设置下面的参数即可
val conf = new SparkConf()
conf.setAppName("ts-bigdata-v2")
.set("spark.streaming.stopGracefullyOnShutdown","true")
.setMaster("local[*]")
二、如果是部署到集群上的程序可以通过以下方式去解决:
主要思路:使用HDFS系统做消息通知,
在驱动程序中,加一段代码,这段代码的作用每隔一段时间可以是10秒也可以是3秒,扫描HDFS上某一个文件,如果发现这个文件存在,就调用StreamContext对象stop方法,自己优雅的终止自己,其实这里HDFS可以换成redis,zk,hbase,db都可以,这里唯一的问题就是依赖了外部的一个存储系统来达到消息通知的目的,如果使用了这种方式后。停止流程序就比较简单了,登录上有hdfs客户端的机器,然后touch一个空文件到指定目录,然后等到间隔的扫描时间到之后,发现有文件存在,就知道需要关闭程序了。
具体实现如下:
def main(args:Array[String]){
val conf = new SparkConf()
conf.setAppName("ts-bigdata-v2")
.setMaster("local[*])
val sc=new SparkContext(conf)
val ssc=new StreamingContext(sc,Seconds(5))
........
ssc.start()
//增加的程序,每5秒检测指定hdfs文件有无文件,如果存在则调用stop接口去停止进程
stopByMarkFile(ssc)
ssc.awaitTermination()
ssc.stop()
}
/**
* 每隔一段时间检查是否存在stop进程的文件,如果存在则结束该进程。
* 前提:
* 会在所有消息处理完成后结束进程
* @param ssc
*/
def stopByMarkFile(ssc:StreamingContext):Unit= {
val intervalMills = 5 * 1000 // 每隔30秒扫描一次消息是否存在
var isStop = false
val master = "hdfs://IP:端口"
val path = "/user/new_user/stop" //判断消息文件是否存在,如果存在就
while (!isStop) {
isStop = ssc.awaitTerminationOrTimeout(intervalMills)
if (!isStop && isExistsMarkFile(master+path)) {
println("5秒后开始关闭sparstreaming程序.....")
Thread.sleep(30000)
ssc.stop(true, true)
delHdfsFile(master,path)
}else{
println("***********未检测到有停止信号*****************")
}
}
}
/**
* 判断文件是否存在
* @param hdfs_file_path
* @return
*/
def isExistsMarkFile(hdfs_file_path:String):Boolean={
val conf = new Configuration()
val path=new Path(hdfs_file_path)
val fs =path.getFileSystem(conf)
fs.exists(path)
}
如何测试:
可以写一个简单的接口程序,去生成“"hdfs://IP:端口/user/new_user/stop”文件。
文件生成后,可以观察上面程序的进程。
问题解决