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,它支持消费者组并处理故障转移,但不支持许多 ...
随机推荐
- flask中SQLAlchemy学习
------------------------------------2019-08-22 17:53:54更新------------------------------ SQLALchemy实在 ...
- pandas 移动列的方法
import pandas as pd df = pd.DataFrame(np.random.randn(3,4),columns=['a','b','c','d']) k = df.pop(&qu ...
- 落谷 P4052 [JSOI2007]文本生成器
题目链接.只要有一个可读就行,容斥会好做一点. 可读数量 \(=\) 总数 \(-\) 不可读数量 总数显然是 \(26 ^ n\). 求解不可读数量 不可读数量可以利用 AC 自动机的模型进行 DP ...
- 5.深入Istio源码:Pilot-agent作用及其源码分析
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的Istio源码是 release 1.5. 介绍 Sidecar在注入的时候会 ...
- 【Django admin 中文配置】
打开settings.py文件,找到语言编码.时区的设置项,将内容改为如下: [其中 zh-Hans是简体中文 zh-Hant是繁体中文] LANGUAGE_CODE = 'zh-Hans' # LA ...
- 关于django python manage.py startapp 应用名 出错异常原因
如题,在控制台运行python manage.py startapp sales 建立一个应用报错异常 1.应用名不能包含下划线等字符 所以app-demo 不能作为应用名被定义 2.manage.p ...
- svn工具包+安装教程+使用ip访问
SVN使用 简介: SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. Server界面 1: 安装这两个文 ...
- Kafka消费者手动提交消息偏移
生产者每次调用poll()方法时,它总是返回由生产者写入Kafka但还没有消费的消息,如果消费者一致处于运行状态,那么分区消息偏移量就没什么用处,但是如果消费者发生崩溃或者有新的消费者加入群组,就会触 ...
- abp.zero 9.0框架的前端Angular使用说明
abp.zero 9.0框架的前端Angular使用说明 目录 abp.zero 9.0框架的前端Angular使用说明 摘要 1 部署及启动 1.1 依赖包安装 1.2 使用yarn安装依赖包 1. ...
- numpy和pandas-数据分析模块
应用:1.数据分析 2.深度学习 3.机器学习 运算速度快:numpy 和 pandas 都是采用 C 语言编写, pandas 又是基于 numpy, 是 numpy 的升级版本. 消耗资源少:采用 ...