kafka 0.8+spark offset 提交至mysql
kafka版本:<kafka.version> 0.8.2.1</kafka.version>
spark版本 <artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
object DmRealStat {
def main(args: Array[String]): Unit = {
/**
* 1.集成kafka进行数据进行数据读取
* 程序第一次启动从数据库获取偏移量,开始读取
*/
val sparkConf = new SparkConf().setMaster("local[4]").setAppName("实时监控")
//开启背压 开启后spark自动根据系统负载选择最优消费速率
sparkConf.set("spark.streaming.backpressure.enabled", "true")
//spark.streaming.backpressure.initialRate (整数) 默认直接读取所有
sparkConf.set(" spark.streaming.backpressure.initialRate", "1000")
//(4)限制每秒每个消费线程读取每个kafka分区最大的数据量 (整数) 默认直接读取所有
sparkConf.set(" spark.streaming.kafka.maxRatePerPartition ", "500")
sparkConf.set("spark.streaming.stopGracefullyOnShutdown", "true")
// sparkConf.set("spark.driver.memory","2G")
val ssc = new StreamingContext(sparkConf, Seconds(2))
val sc = ssc.sparkContext
//sparksql
val spark = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
//程序第一次启动,无偏移量
/*
def createDirectStream[
K: ClassTag, key的类型
V: ClassTag, value的类型
KD <: Decoder[K]: ClassTag,
VD <: Decoder[V]: ClassTag] (
ssc: StreamingContext,
kafkaParams: Map[String, String],
topics: Set[String]
): InputDStream[(K, V)] = {
val messageHandler = (mmd: MessageAndMetadata[K, V]) => (mmd.key, mmd.message)
val kc = new KafkaCluster(kafkaParams)
val fromOffsets = getFromOffsets(kc, kafkaParams, topics)
new DirectKafkaInputDStream[K, V, KD, VD, (K, V)](
ssc, kafkaParams, fromOffsets, messageHandler)
}
*/
val conf = ConfigFactory.load()
val brokers = conf.getString("kafka.broker.list")
val topic = conf.getString("kafka.topic")
val groupid = "11"
val kafkaParams = Map(
"metadata.broker.list" -> brokers,
"auto.offset.reset" -> "smallest",
"group.id" -> groupid
)
//加载配置信息 默认加载default.jdbc 如需设置生产环境 scalajdbcTest
DBs.setup()
val fromOffsets: Map[TopicAndPartition, Long] = DB.readOnly { implicit session =>
sql"select topic,partitions,offset from stream_offset where groupid=? and topic=? and brokerlist=?".bind(groupid, topic, brokers).map(rs => {
(TopicAndPartition(rs.get[String]("topic"), rs.get[Int]("partitions")), rs.long("offset"))
}).list().apply()
}.toMap
val topics = Set(topic)
val stream = if (fromOffsets.size == 0) {
// 程序第一次启动
KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, topics)
}
else {
//程序非第一次启动
var checkOffset = Map[TopicAndPartition, Long]()
//思考:kafka默认的保存数据是7天 但在过程中在没有启动过消费者 ,保存的offset是过期的偏移量 所以
// 必须查询偏移量与当前有效的最早的偏移量进行比较 如果保存的比当前的小,说明过期了
val kafkaCluste = new KafkaCluster(kafkaParams);
//传进去TopicAndPartition
val earliestLeaderOffsets = kafkaCluste.getEarliestLeaderOffsets(fromOffsets.keySet)
if (earliestLeaderOffsets.isRight) {
//得到了分区和对应的偏移量
val topicAndOffset: Map[TopicAndPartition, KafkaCluster.LeaderOffset] = earliestLeaderOffsets.right.get
checkOffset = fromOffsets.map(selectOffset => {
//拿到当前集群的分区 最早偏移量
val currentOffset = topicAndOffset.get(selectOffset._1).get.offset
if (selectOffset._2 >= currentOffset) {
//数据库的大于当前集群的 就使用数据库offfset
selectOffset
} else {
(selectOffset._1, currentOffset)
// val a= new KafkaConsumer(Map[String,Object](""->"")
}
})
checkOffset
}
//此处从数据库获取偏移量 ,程序启动从此处开始往后消费
val messageHandler = (mm: MessageAndMetadata[String, String]) => {
(mm.key(), mm.message())
}
KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder, (String, String)](ssc, kafkaParams, checkOffset, messageHandler)
}
//2.处理数据
stream
.foreachRDD(kafkardd => {
// val a: RDD[(String, String)] =kafkardd
val mapdata = LogUtils.logParse(kafkardd.map(_._2)).filter(log => log.contains("en") && log("en") == "e_dm")
mapdata.foreach(println(_))
var minute = ""
//2实时进行审核信息统计
//看一下偏移量
//3.自主管理偏移量存入redis/或者mysql
val offsetRanges = kafkardd.asInstanceOf[HasOffsetRanges].offsetRanges
offsetRanges.foreach(offsetRange => {
DB.autoCommit(implicit session =>
sql"replace into stream_offset(topic,partitions,groupid,brokerlist,offset)values (?,?,?,?,?)".bind(
offsetRange.topic,
offsetRange.partition,
groupid,
brokers,
offsetRange.untilOffset
).update().apply()
)
println("topic:" + offsetRange.topic + "分区:" + offsetRange.partition + "开始消费" + offsetRange.fromOffset + "消费到" + offsetRange.untilOffset + "共计" + offsetRange.count())
}
)
})
ssc.start()
ssc.awaitTermination()
}
def dongmanStat(mapdata:RDD[mutable.Map[String,String]]): Unit ={
val baseData = mapdata.filter(map => map.contains("c_type_name") && map.contains("status")).map(_map => {
val baseData = mapdata.map(_map => {
// String contId = _map.get("c_id");
// String cpId = _map.get("cp_id");
// String contTypeName = _map.get("c_type_name");
// String status = _map.get("status");
// String duration = _map.get("dura");
// String operator = _map.get("operator");
// String bcTime = _map.get("bc_time");
val minute = _map("s_time").substring(0, 12)
val day = _map("s_time").substring(0, 8)
val c_type = _map("c_type_name");
val progId = _map("cp_id");
val bcTotal = if (_map("status").toInt >= 8) 1 else 0
val receive = if (_map("status").toInt == 8) 1 else 0
val waitingBc = if (_map("status").toInt == 8) 1 else 0
val bcPerson = _map.getOrElse("operator", " ");
val syncTime = _map.getOrElse("sync_time", "");
// val srcLog = _map.getOrElse("src_log");
// val isDel = _map.getOrElse("is_delete",0)
// val isBcReview = _map.getOrElse("is_bc_review","")
(day, c_type, progId, bcPerson, syncTime, List[Int](bcTotal, receive, waitingBc))
})
// //内容统计
// val contBcStat = baseData.map {
// case (day, contId, progId, bcPerson, syncTime, list) => {
// ((day, contId), list)
// }
// }.distinct().reduceByKey((list1, list2) => {
// list1.zip(list2).map(i => {
// i._1 + i._2
// })
// }).foreachPartition(rdd => {
// val jedis = JedisUtil.getJedisClient()
// rdd.foreach(data => {
// val key: String = "cidStat" + "_" + data._1._1
// val a = jedis.hincrBy(key, "bcTotal", data._2(0))
// if (a > 0) println("自增成功") else println("自增失败")
// jedis.hincrBy(key, "receive", data._2(1))
// jedis.hincrBy(key, "waitingBc", data._2(2) - data._2(0))
// })
// jedis.close()
// })
//播控人内容统计 如果是相同的内容播控 条数去重
val bcPersonStat = baseData.map(t => ((t._1, t._4, t._2))).distinct()
// .updateStateByKey[Long]((seq: Seq[Int], state: Option[Long]) => {
// //seq:Seq[Long] 当前批次中每个相同key的value组成的Seq
// val currentValue = seq.sum
// //state:Option[Long] 代表当前批次之前的所有批次的累计的结果,val对于wordcount而言就是先前所有批次中相同单词出现的总次数
// val preValue = state.getOrElse(0L)
// Some(currentValue + preValue)
// })
.map(t => ((t._1, t._2), 1))
.reduceByKey(_ + _)
.foreachPartition(rdd => {
val jedis = JedisUtil.getJedisClient()
rdd.foreach(data => {
val key: String = data._1._1 + "_" + data._1._2
jedis.hincrBy(key, "bcPersonStat", data._2.toLong)
})
//不释放的 会发生线程阻塞 无法进行数据插入
jedis.close()
})
})
}
kafka 0.8+spark offset 提交至mysql的更多相关文章
- kafka 0.11 spark 2.11 streaming例子
""" Counts words in UTF8 encoded, '\n' delimited text received from the network every ...
- SparkStreaming消费Kafka,手动维护Offset到Mysql
目录 说明 整体逻辑 offset建表语句 代码实现 说明 当前处理只实现手动维护offset到mysql,只能保证数据不丢失,可能会重复 要想实现精准一次性,还需要将数据提交和offset提交维护在 ...
- Offset Management For Apache Kafka With Apache Spark Streaming
An ingest pattern that we commonly see being adopted at Cloudera customers is Apache Spark Streaming ...
- Kafka 0.9+Zookeeper3.4.6集群搭建、配置,新Client API的使用要点,高可用性测试,以及各种坑 (转载)
Kafka 0.9版本对java client的api做出了较大调整,本文主要总结了Kafka 0.9在集群搭建.高可用性.新API方面的相关过程和细节,以及本人在安装调试过程中踩出的各种坑. 关于K ...
- Kafka 0.10 KafkaConsumer流程简述
ConsumerConfig.scala 储存Consumer的配置 按照我的理解,0.10的Kafka没有专门的SimpleConsumer,仍然是沿用0.8版本的. 1.从poll开始 消费的规则 ...
- Structured Streaming从Kafka 0.8中读取数据的问题
众所周知,Structured Streaming默认支持Kafka 0.10,没有提供针对Kafka 0.8的Connector,但这对高手来说不是事儿,于是有个Hortonworks的邵大牛(前段 ...
- Kafka 0.11.0.0 实现 producer的Exactly-once 语义(中文)
很高兴地告诉大家,具备新的里程碑意义的功能的Kafka 0.11.x版本(对应 Confluent Platform 3.3)已经release,该版本引入了exactly-once语义,本文阐述的内 ...
- 【Spark】提交Spark任务-ClassNotFoundException-错误处理
提交Spark任务-ClassNotFoundException-错误处理 Overview - Spark 2.2.0 Documentation Spark Streaming - Spark 2 ...
- Apache Kafka 0.9消费者客户端
当Kafka最初创建时,它与Scala生产者和消费者客户端一起运送.随着时间的推移,我们开始意识到这些API的许多限制.例如,我们有一个“高级”消费者API,它支持消费者组并处理故障转移,但不支持许多 ...
随机推荐
- PC微信[多开+免扫码+防撤回撤回提示+转存语音+自动收款+远程命令]
PC端微信玩出了新花样,主要技术为Hook技术 有兴趣的小伙伴可以去了解下hook钩子技术 版本介绍: 增加转存语音到MP3(保存你重要的语音数据) 增加表图转存; 增加自动收转账和自动回复; 增加远 ...
- Dwango Programming Contest 6th E 题解
题目大意 你有一条区间\([0, X)\),并且有一个数组\(L_1, ..., L_n\).对于任意\(1 \leq i \leq n\),你可以指定一个非负整数\(0 \leq j_i \leq ...
- 题解-CF1401E Divide Square
题面 CF1401E Divide Square 给一个正方形平面边长为 \(10^6\),给 \(n\) 条横线段和 \(m\) 条竖线段,每条线段都与正方形边缘相交且一条直线上不会有两条线段,求被 ...
- 配置 Spring Batch 批处理失败重试机制
1. 引言 默认情况下,Spring批处理作业在执行过程中出现任何错误都会失败.然而有些时候,为了提高应用程序的弹性,我们就需要处理这类间歇性的故障. 在这篇短文中,我们就来一起探讨 如何在Sprin ...
- js日期格式化-----总结
1. // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 ...
- (数据科学学习手札100)搞定matplotlib中的字体设置
本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 matplotlib作为数据可视化的利器,被广泛 ...
- 服务启动Apache服务,错误Parent: child process exited with status 3 -- Aborting.解决
不能启动apache,或者使用wamp等集成包后,唯独apache服务启动后有停止,但是把东西搬到其他机器上却没事问题可能和网络有关,我查了很多资料首先找打apache的错误报告日志,发现现实诸多的调 ...
- Graphql Tutorials(Episode 01)
1.前言 最近认识到Graphql,它是一个基于DSL的api.我曾接触过一个pos机刷卡系统,它是基于JSON-DSL语言开发的框架,很有趣.可是后来,没有机会深入研究.直到最近我认识了Graphq ...
- 移动 drag&drop拖放
拖放事件 #1. 三个对象 源对象 -- 被拖放的元素 过程对象 -- 经过的元素 目标对象 -- 到达的元素 #2. 源对象中的事件 要想让某个元素可以拖拽需要设置draggable=" ...
- [游记]FCS&FJOI2018滚粗记
省冬连着省选,嗯这篇博客是省冬前就开的 省选是在情人节前一天- day0 中午早早的来了这边(找了个酒店到房间发现非常粉w 下午一个人去附中报到,然而-没有人带队签安全责任书好像不行-签到失败QAQ ...