场景
上游数据同步mysql的binlog数据并推到kafka,我们作为下游需要将数据接过来,进行处理,之后存入对外提供服务的数据库中。
方案
使用Spark Streaming消费kafka实现近实时的效果,使用kafka低级api direct的方式,来接收数据
direct 方式会周期性地查询Kafka,来获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当开始处理数据时,会获取指定offset范围的数据,当前批数据完全处理完成之后,再将offset提交,可以保证至少一次的特性。
如果数据丢在kafka自身的环节,由于每个topic是有副本的,可以通过副本机制找回。
如果是消费程序挂掉导致的数据缺失,由于上次的偏移量范围对应的batch没有处理成功,再次重启程序的时候,只会从上次成功的offset出开始消费,以此实现至少一次的语义。
code
val topic = tables.map("bb_" + _).toSet[String]
//获得sparkContext对象
val sc = SparkConfig.getSparkSession(s"kafka-streaming").sparkContext
//创建streamingContext
val ssc = new StreamingContext(sc,Milliseconds(millSeconds))
//kafka 配置
val kafkaParams = Map[String,Object](
"bootstrap.servers" -> "xxxx:9092,xxxx:9092,xxxx:9092",
"group.id" -> "xxxx",
"auto.offset.reset" -> "earliest",
//上游数据是avro格式的,配置avro schema registry解析arvo数据
"schema.registry.url" -> "http://192.168.100.182:8081",
"key.deserializer" -> classOf[StringDeserializer],
//值是avro数据,需要通过KafkaAvroDeserializer反序列化
"value.deserializer" -> classOf[KafkaAvroDeserializer],
//自己来决定什么时候提交offset
"enable.auto.commit" -> (false: java.lang.Boolean)
)
//使用的kafka010版本的api
val kafkaStream = KafkaUtils.createDirectStream[String,Object](
ssc,
//持久化策略
PreferConsistent,
//订阅信息
Subscribe[String,Object](topic, kafkaParams)
)
//处理每个微批的rdd
kafkaStream.foreachRDD( rdd => {
if(rdd!=null && !rdd.isEmpty()){
//获取偏移量
val offsetRange = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
//对每个分区分别处理
rdd.foreachPartition( iterator => {
if( iterator != null && !iterator.isEmpty ){
//作相应的处理
while (iterator.hasNext) {
//处理每一条记录
val next = iterator.next
//这个就是接收到的数据值对象,
val record = next.value().asInstanceOf[Record]
//可以插入数据库,或者输出到别的地方
...
}
}
})
//将偏移量提交(偏移量是提交到kafka管理的)
kafkaStream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRange)
println("submit offset!")
}
})
ssc.start()
ssc.awaitTermination()
pom
列出了反序列化avro和sparkstreaming结合kafka010的依赖,备忘
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-avro-serializer</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
<version>2.3.1</version>
</dependency>
相关链接
spark官方文档: http://spark.apache.org/docs/latest/streaming-kafka-0-10-integration.html
sparkstreaming kafka demo: https://dongkelun.com/2018/06/20/sparkStreamingOffsetOnlyOnce/
kafka 08和010概述: https://blog.csdn.net/weixin_43228814/article/details/88889894
spark消费kafka两种方式的区别: https://blog.csdn.net/qq_41571900/article/details/84205181
简单的应用层面,如果有不对的地方欢迎指正。