spark streaming中维护kafka偏移量到外部介质

以kafka偏移量维护到redis为例。

redis存储格式

使用的数据结构为string,其中key为topic:partition,value为offset

例如bobo这个topic下有3个分区,则key-value结构如下:

  • bobo:0的偏移量为x
  • bobo:1的偏移量为y
  • bobo:2的偏移量为z

消费时指定offset

主要是如下两个方法:

  • createKafkaStream()创建kakfa流
  • getOffsets()从redis中获取offsets
/**
* kakfa参数
*/
private val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "crpprdap25:6667,crpprdap26:6667,crpprdap27:6667",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "use_a_separate_group_id_for_each_stream",
// 注意这里是none。
"auto.offset.reset" -> "none",
"enable.auto.commit" -> (false: java.lang.Boolean)
) // `bobo`topic下有3个分区
private val topicPartitions = Map[String, Int]("bobo" -> 3) // 从redis中获取offsets
def getOffsets: Map[TopicPartition, Long] = {
val jedis = InternalRedisClient.getResource // 设置每个分区起始的offset
val offsets = mutable.Map[TopicPartition, Long]() topicPartitions.foreach { it =>
val topic = it._1
val partitions = it._2
// 遍历分区,设置每个topic下对应partition的offset
for (partition <- 0 until partitions) {
val topicPartitionKey = topic + ":" + partition
var lastOffset = 0L
val lastSavedOffset = jedis.get(topicPartitionKey) if (null != lastSavedOffset) {
try {
lastOffset = lastSavedOffset.toLong
} catch {
case e: Exception =>
log.error("get lastSavedOffset error", e)
System.exit(1)
}
}
log.info("from redis topic: {}, partition: {}, lastOffset: {}", topic, partition, lastOffset) // 添加
offsets += (new TopicPartition(topic, partition) -> lastOffset)
}
} InternalRedisClient.returnResource(jedis) offsets.toMap
} /**
* 创建kakfa流
*
* @param ssc StreamingContext
* @return InputDStream
*/
def createKafkaStream(ssc: StreamingContext): InputDStream[ConsumerRecord[String, String]] = {
val offsets = getOffsets // 创建kafka stream
val stream = KafkaUtils.createDirectStream[String, String](
ssc,
LocationStrategies.PreferConsistent,
ConsumerStrategies.Assign[String, String](offsets.keys.toList, kafkaParams, offsets)
)
stream
}

其中:核心是通过ConsumerStrategies.Assign方法来指定topic下对应partitionoffset信息。

更新offset到redis

最后将offset信息维护到redis即可。

/**
* 消费
*
* @param stream InputDStream
*/
def consume(stream: InputDStream[ConsumerRecord[String, String]]): Unit = {
stream.foreachRDD { rdd =>
// 获取offset信息
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges // 计算相关指标,这里就统计下条数了
val total = rdd.count() val jedis = InternalRedisClient.getResource
val pipeline = jedis.pipelined()
// 会阻塞redis
pipeline.multi() // 更新相关指标
pipeline.incrBy("totalRecords", total) // 更新offset
offsetRanges.foreach { offsetRange =>
log.info("save offsets, topic: {}, partition: {}, offset: {}", offsetRange.topic, offsetRange.partition, offsetRange.untilOffset)
val topicPartitionKey = offsetRange.topic + ":" + offsetRange.partition
pipeline.set(topicPartitionKey, offsetRange.untilOffset + "")
} // 执行,释放
pipeline.exec()
pipeline.sync()
pipeline.close()
InternalRedisClient.returnResource(jedis)
}
}

参考

spark代码

顺便贴一下自己整理的spark相关的代码。

Github地址:spark-programming

主要包括:

  • RDD的基本使用
  • SQL
    • jdbc(读、写)
    • hive(读、写、动态分区)
  • Streaming
    • 消费kafka(手动提交、手动维护offset)
    • 写入HBase
    • 写入Hive

spark streaming中维护kafka偏移量到外部介质的更多相关文章

  1. Spark Streaming中的操作函数分析

    根据Spark官方文档中的描述,在Spark Streaming应用中,一个DStream对象可以调用多种操作,主要分为以下几类 Transformations Window Operations J ...

  2. Spark Streaming中的操作函数讲解

    Spark Streaming中的操作函数讲解 根据根据Spark官方文档中的描述,在Spark Streaming应用中,一个DStream对象可以调用多种操作,主要分为以下几类 Transform ...

  3. flink⼿手动维护kafka偏移量量

    flink对接kafka,官方模式方式是自动维护偏移量 但并没有考虑到flink消费kafka过程中,如果出现进程中断后的事情! 如果此时,进程中段: 1:数据可能丢失 从获取了了数据,但是在执⾏行行 ...

  4. Spark Streaming中向flume拉取数据

    在这里看到的解决方法 https://issues.apache.org/jira/browse/SPARK-1729 请是个人理解,有问题请大家留言. 其实本身flume是不支持像KAFKA一样的发 ...

  5. flink和spark Streaming中的Back Pressure

    Spark Streaming的back pressure 在讲flink的back pressure之前,我们先讲讲Spark Streaming的back pressure.Spark Strea ...

  6. Flink与Spark Streaming在与kafka结合的区别!

    本文主要是想聊聊flink与kafka结合.当然,单纯的介绍flink与kafka的结合呢,比较单调,也没有可对比性,所以的准备顺便帮大家简单回顾一下Spark Streaming与kafka的结合. ...

  7. Spark Streaming中动态Batch Size实现初探

    本期内容 : BatchDuration与 Process Time 动态Batch Size Spark Streaming中有很多算子,是否每一个算子都是预期中的类似线性规律的时间消耗呢? 例如: ...

  8. spark streaming中使用flume数据源

    有两种方式,一种是sparkstreaming中的driver起监听,flume来推数据:另一种是sparkstreaming按照时间策略轮训的向flume拉数据. 最开始我以为只有第一种方法,但是尼 ...

  9. Spark Streaming 实现读取Kafka 生产数据

    在kafka 目录下执行生产消息命令: ./kafka-console-producer  --broker-list nodexx:9092 --topic  201609 在spark bin 目 ...

随机推荐

  1. POI操作excle

    将根目录下的poi-3.6-20091214.jar和Lib目录下三个通用包 commons-logging-1.1.jar junit-3.8.1.jar log4j-1.2.13.jar拷贝到项目 ...

  2. 【转载】PyTorch系列 (二):pytorch数据读取

    原文:https://likewind.top/2019/02/01/Pytorch-dataprocess/ Pytorch系列: PyTorch系列(一) - PyTorch使用总览 PyTorc ...

  3. 通用RSA加密 - PHP+Java+Javascript加密解密

    php端生成 公钥私钥 1.openssl genrsa -out rsa_private_key.pem 1024    私钥 2.openssl rsa -in rsa_private_key.p ...

  4. zynq DMA控制器

    Zynq-7000系列器件PS端的DMA控制器采用ARM的IP核DMA-330(PL-330)实现. 特点: 1.8个独立的通道,4个可用于PL—PS间数据管理,每个通道有1024Byte的MFIFO ...

  5. 多个python版本共存

    windows下多个python版本共存 了解python的人都知道python有2.x版本和3.x版本,而python3.x版本不向下兼容,但是根据具体的需要,有时候要2.x和3.x共存,pytho ...

  6. 微信小程序的桌面图标问题

    提问: 笔者在发布小程序后,发现无法在安卓手机创建桌面图标,而其它的小程序却可以. 回答: 在小程序后台页面(从公众平台进入)完整填写小程序的信息,之后便可创建桌面图标. 这可能是微信的某种筛查机制在 ...

  7. h1-h3使用

    一个页面也就只允许出现一个h1标签.内容页文章的标题,是seo中使用最多的地方,基本的文章页面标题都是使用h1标签.一.<h1>用来修饰网页的主标题,一般是网页的标题 ,文章标题,< ...

  8. 先进过程控制之一:浅说APC

    先进过程控制(APC)技术作为在生产装置级的信息化应用,在优化装置的控制水平和提高生产过程的管理水平的同时,还为企业创造了可观的经济效益. 1.什么是APC 先进过程控制,简称APC,并不是什么新概念 ...

  9. 【彻底解决】django migrate (mysql.W002) 【专治强迫症】

    cmd中使用python3 manage.py migrate命令,报warn,很多人都遇到过 解决办法: settings.py文件夹加入DATABASES['OPTIONS']['init_com ...

  10. MYSQL的安全模式:sql_safe_updates介绍

    什么是安全模式 在mysql中,如果在update和delete没有加上where条件,数据将会全部修改.不只是初识mysql的开发者会遇到这个问题,工作有一定经验的工程师难免也会忘记写入where条 ...