首先要知道什么是checkpoint?checkpoint就是检查点,用于核查rdd的进度。
比如说一长串rdd计算操作需要花费很长时间,占用资源也比较多,突然断电,服务器宕机等等不可预测事情发生时候,这个时候如何rdd从新计算将又要花费大量时间,占用大量资源,这就耗时耗力了,spark的checkpoint就是为了解决这个问题而生的。
checkpoint先把rdd的中间重要计算结果保存到hdfs上,下次计算时候不需要从新计算,直接读取hdfs上文件,这样能快很多。
实现checkpoint方法有很多,可以存到数据库中,比如mysql,也可以存到hdfs上保存。
下面我分别用两种方法保存checkpoint。
**
第一种方法:用数据库保存checkpoint,以mysql为例**
val socket: ReceiverInputDStream[String] = ssc.socketTextStream("hdp-03", 9999)
socket.foreachRDD(rdd => {
val config: Config = ConfigFactory.load()
// rdd非空 ,才统计
if (!rdd.isEmpty()) {
// 当前批次的数据
val curDat: RDD[(String, Int)] = rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
curDat.foreachPartition { case it =>
// 获取连接
val conn = DriverManager.getConnection(
config.getString("db.url"),
config.getString("db.user"),
config.getString("db.passwd"))
// 获取操作的数据库表
val table = config.getString("db.tablename")
it.foreach{
case (word, curCnts) => {
val pstm = conn.prepareStatement(s"create table if not exists ${table} (word varchar(20), cnts int )")
pstm.executeUpdate()
// 查询 key 是否存在
val pstm1: PreparedStatement = conn.prepareStatement(s"select * from ${table} where word = ?")
pstm1.setString(1, word)
// 查询
val set: ResultSet = pstm1.executeQuery()
if (set.next()) {// 有数据
// 获取次数
val hisDat = set.getInt("cnts")
val total = hisDat + curCnts
// 更新历史数据
val pstm2: PreparedStatement = conn.prepareStatement(s"update ${table} set cnts = ? where word = ?")
pstm2.setInt(1,total)
pstm2.setString(2,word)
pstm2.executeUpdate()
} else { // key在历史数据中不存在 直接入库
val pstm3 = conn.prepareStatement(s"insert into ${table} values (?,?)")
pstm3.setString(1,word)
pstm3.setInt(2,curCnts)
pstm3.execute()
}
}}
}
}
})
**
**
## 第二种方法:存到hdfs上保存
**
**
// 设置checkpoint的目录
val ckdir = “ck-2019”
// 所有的业务逻辑,所有的配置,全部放在该函数中
val creatingFunc = () => {
val conf = new SparkConf()
.setMaster(“local[*]”) // cores 至少是2个
.setAppName(this.getClass.getSimpleName)
val ssc: StreamingContext = new StreamingContext(conf, Seconds(2))
ssc.checkpoint(ckdir)
val socket: ReceiverInputDStream[String] = ssc.socketTextStream(“hdp-03”, 9999)
// updateFunc: (Seq[V], Option[S]) => Option[S]
// hello,Seq[1,1,1,1,1] Some(10)
// spark,Seq[1,1] None
val updateFunc = (currentDat: Seq[Int], hisDat: Option[Int]) => {
val totalValue = hisDat.getOrElse(0) + currentDat.sum
Some(totalValue)
}
val wordWithOne: DStream[(String, Int)] = socket.flatMap(.split(" +")).map((, 1))
val result: DStream[(String, Int)] = wordWithOne.updateStateByKey(updateFunc)
result.print()
// 返回一个StreamingContext
ssc
}
def main(args: Array[String]): Unit = {
// StreamingContext 如果存在就直接拿来使用,不存在,才去创建
val ssc: StreamingContext = StreamingContext.getOrCreate(ckdir, creatingFunc)
ssc.start()
ssc.awaitTermination()
}