使用场景

Spark Streaming实时消费kafka数据的时候,程序停止或者Kafka节点挂掉会导致数据丢失,Spark Streaming也没有设置CheckPoint(据说比较鸡肋,虽然可以保存Direct方式的offset,但是可能会导致频繁写HDFS占用IO),所以每次出现问题的时候,重启程序,而程序的消费方式是Direct,所以在程序down掉的这段时间Kafka上的数据是消费不到的,虽然可以设置offset为smallest,但是会导致重复消费,重新overwrite hive上的数据,但是不允许重复消费的场景就不能这样做。

原理阐述

在Spark Streaming中消费 Kafka 数据的时候,有两种方式分别是 :

1.基于 Receiver-based 的 createStream 方法。receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming启动的job会去处理那些数据。然而,在默认的配置下,这种方式可能会因为底层的失败而丢失数据。如果要启用高可靠机制,让数据零丢失,就必须启用Spark Streaming的预写日志机制(Write Ahead Log,WAL)。该机制会同步地将接收到的Kafka数据写入分布式文件系统(比如HDFS)上的预写日志中。所以,即使底层节点出现了失败,也可以使用预写日志中的数据进行恢复。本文对此方式不研究,有兴趣的可以自己实现,个人不喜欢这个方式。KafkaUtils.createStream

2.Direct Approach (No Receivers) 方式的 createDirectStream 方法,但是第二种使用方式中  kafka 的 offset 是保存在 checkpoint 中的,如果程序重启的话,会丢失一部分数据,我使用的是这种方式。KafkaUtils.createDirectStream。本文将用代码说明如何将 kafka 中的 offset 保存到 zookeeper 中,以及如何从 zookeeper 中读取已存在的 offset。

代码

废话不说,直接贴代码。


  import kafka.common.TopicAndPartition
  import kafka.message.MessageAndMetadata
  import kafka.serializer.StringDecoder
  import kafka.utils.{ZKGroupTopicDirs, ZkUtils}
  import org.I0Itec.zkclient.ZkClient
  import org.apache.spark.streaming.{Seconds, StreamingContext}
  import org.apache.spark.streaming.dstream.InputDStream
  import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaUtils, OffsetRange}
   val conf: Conf = new config.Conf("test-util.conf")
val zkHost = conf.getString("kafka.zookeeper.connect")
val brokerList=conf.getString("kafka.metadata.broker.list")
val zkClient = new ZkClient(zkHost)
val kafkaParams = Map[String, String]("metadata.broker.list" -> brokerList,
"zookeeper.connect" -> zkHost,
"group.id" -> "testid") var kafkaStream: InputDStream[(String, String)] = null
var offsetRanges = Array[OffsetRange]()
val sc=SparkUtil.createSparkContext("test")
val ssc=new StreamingContext(sc,Seconds(5))
val topic="TEST_TOPIC"
val topicDirs = new ZKGroupTopicDirs("TEST_TOPIC_spark_streaming_testid", topic) //创建一个 ZKGroupTopicDirs 对象,对保存 val children = zkClient.countChildren(s"${topicDirs.consumerOffsetDir}") //查询该路径下是否字节点(默认有字节点为我们自己保存不同 partition 时生成的) var fromOffsets: Map[TopicAndPartition, Long] = Map() //如果 zookeeper 中有保存 offset,我们会利用这个 offset 作为 kafkaStream 的起始位置 if (children > 0) { //如果保存过 offset,这里更好的做法,还应该和 kafka 上最小的 offset 做对比,不然会报 OutOfRange 的错误
for (i <- 0 until children) {
val partitionOffset = zkClient.readData[String](s"${topicDirs.consumerOffsetDir}/${i}")
val tp = TopicAndPartition(topic, i)
fromOffsets += (tp -> partitionOffset.toLong) //将不同 partition 对应的 offset 增加到 fromOffsets 中
} val messageHandler = (mmd : MessageAndMetadata[String, String]) => (mmd.topic, mmd.message()) //这个会将 kafka 的消息进行 transform,最终 kafak 的数据都会变成 (topic_name, message) 这样的 tuple
kafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder, (String, String)](ssc, kafkaParams, fromOffsets, messageHandler)
}
else {
kafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, Set("TEST_TOPIC")) //如果未保存,根据 kafkaParam 的配置使用最新或者最旧的 offset
} kafkaStream.transform{rdd=>
offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges //得到该 rdd 对应 kafka 的消息的 offset
rdd
}.map(_._2).foreachRDD(rdd=>{
for (o <- offsetRanges) {
val zkPath = s"${topicDirs.consumerOffsetDir}/${o.partition}"
ZkUtils.updatePersistentPath(zkClient, zkPath, o.fromOffset.toString) //将该 partition 的 offset 保存到 zookeeper
}
rdd.foreach(s=>println(s))
}) ssc.start()
ssc.awaitTermination()

总结

楼主实现了保存一个topic的offset到zk,但是如果Spark Streaming同时消费多个topic的方式及topicSet里有多个topic,楼主还没有想到解决办法,欢迎指正。

Spark Streaming消费Kafka Direct方式数据零丢失实现的更多相关文章

  1. Spark Streaming和Kafka整合保证数据零丢失

    当我们正确地部署好Spark Streaming,我们就可以使用Spark Streaming提供的零数据丢失机制.为了体验这个关键的特性,你需要满足以下几个先决条件: 1.输入的数据来自可靠的数据源 ...

  2. Spark Streaming消费Kafka Direct保存offset到Redis,实现数据零丢失和exactly once

    一.概述 上次写这篇文章文章的时候,Spark还是1.x,kafka还是0.8x版本,转眼间spark到了2.x,kafka也到了2.x,存储offset的方式也发生了改变,笔者根据上篇文章和网上文章 ...

  3. Spark streaming消费Kafka的正确姿势

    前言 在游戏项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从kafka中不 ...

  4. spark streaming 消费 kafka入门采坑解决过程

    kafka 服务相关的命令 # 开启kafka的服务器bin/kafka-server-start.sh -daemon config/server.properties &# 创建topic ...

  5. 用canal同步binlog到kafka,spark streaming消费kafka topic乱码问题

    canal 1.1.1版本之后, 默认支持将canal server接收到的binlog数据直接投递到MQ, 目前默认支持的MQ系统有kafka和RocketMQ. 在投递的时候我们使用的是非压平的消 ...

  6. spark streaming消费kafka: Java .lang.IllegalStateException: No current assignment for partition

    1 原因是: 多个相同的Spark Streaming同时消费同一个topic,导致的offset问题.关掉多余的任务,就ok了.

  7. spark streaming 整合 kafka(一)

    转载:https://www.iteblog.com/archives/1322.html Apache Kafka是一个分布式的消息发布-订阅系统.可以说,任何实时大数据处理工具缺少与Kafka整合 ...

  8. Spark Streaming和Kafka整合开发指南(二)

    在本博客的<Spark Streaming和Kafka整合开发指南(一)>文章中介绍了如何使用基于Receiver的方法使用Spark Streaming从Kafka中接收数据.本文将介绍 ...

  9. Spark Streaming和Kafka整合开发指南(一)

    Apache Kafka是一个分布式的消息发布-订阅系统.可以说,任何实时大数据处理工具缺少与Kafka整合都是不完整的.本文将介绍如何使用Spark Streaming从Kafka中接收数据,这里将 ...

随机推荐

  1. python 发邮件-带附件-文本-html

    #!/usr/bin/python # encoding=utf-8 # Filename: send_email.py from email.mime.image import MIMEImage ...

  2. 5G扫盲

    打开手机,连接wifi,如果想要下载一部自己喜欢的高清电影,一般需要半小时左右的时间.5G时代,你可能花费不到1分钟就能完成这些操作.更快的网速.更多的应用意味着更广阔的市场空间,也意味着更激烈的市场 ...

  3. c#读取INI文件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  4. MySQL基础原创笔记

    对表的增删改操作: 创建表: create table student (          id  int  primary key  auto_increment,          name   ...

  5. ie浏览器,背景色兼容解决方法

    rgba的含义,r代表red,g代表green,b代表blue,a代表透明度.红绿蓝是三原色,所有颜色都可以由这三种颜色拼合而成.比如 rgba(0,0,0,.5)就是透明度为0.5的黑色.现代浏览器 ...

  6. JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁

    IO  是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...

  7. HelloWorld!

            爪哇岛上程序猿,5载忙忙未等闲, 醉里挑灯秒登VPN解决Bug,梦里手撕产品战PM:             但行好事,莫问前程,      泰山崩于前,我依然沐浴更衣焚香沏茶:   ...

  8. storm基础系列之二----zookeeper的作用

    在storm集群中,我们常常使用zookeeper作为协调者.那么具体发挥的是什么作用呢? 概括来说,zookeeper是nimbus和supervisor进行交互的中介.具体来说有二: 1.nimb ...

  9. 生成均值文件mean.binaryproto

    [感谢:http://www.cnblogs.com/denny402/p/5102328.html] compute_image_mean.bin生成均值文件mean.binaryproto: ca ...

  10. Async Programming - 1 async-await 糖的本质(1)

    这一个系列的文章主要来讲 C# 中的语言特性 async-await 在语言层面的本质,我们都知道 await 是编译器进行了一个 rewrite,然而这个 rewrite 并不是直接 rewrite ...