使用场景

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. PADS在注册表中的菜单栏数据

    位于 [HKCU\Software\Mentor Graphics\PADS9_5\PADS Layout\Workspaces\ENU\Default\BCGToolBar-593980] 下的二进 ...

  2. CenOS 7 安装wordpress

    1:Centos安装 php和html yum install httpd -y yum install php -y 2:将 wordpress 拖到目录  /var/www/html 3:浏览器访 ...

  3. Javascript模式(第二章基本技巧)------读书笔记

    本章主要帮助大家写出高质量的JS代码的方法,模式和习惯,例如:避免使用全局变量,使用单个的var变量声明,缓存for循环的长度变量length等 一.尽量避免使用全局变量 1 每一个js环境都有一个全 ...

  4. SQL分页语句

    有关分页 SQL 的资料很多,有的使用存储过程,有的使用游标.本人不喜欢使用游标,我觉得它耗资.效率低:使用存储过程是个不错的选择,因为存储过程是经过预编译的,执行效率高,也更灵活.先看看单条 SQL ...

  5. Access 数据库连接 字符串

    <!--Microsoft.Practices.EnterpriseLibrary.Data.dll 操作引用程序集--> <connectionStrings> <ad ...

  6. 查看Visual Studio异常内容

    If Entity Framework throws a validation exception when saving, Visual Studio reports the message, Va ...

  7. 1.系统生命开发周期(SDLC)

    哎,首先我恭喜我,这学期学了一门老师们都说非常重要,而学生们都说哪里重要的课,它就是与<软件工程>课齐名的<系统分析与设计>!!骚年,不背不记,你就死定了!! 首先俺领你认识一 ...

  8. 小表驱动大表, 兼论exists和in

    给出两个表,A和B,A和B表的数据量, 当A小于B时,用exists select * from A where exists (select * from B where A.id=B.id) ex ...

  9. haproxy +keepalived 原创

    Haproxy+keepalived 原理: HAProxy介绍及其定位 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.根 ...

  10. java.lang.ArrayIndexOutOfBoundsException: 1

    数组越界 但是我这个也不是这个原因: 在CuiShouDetail.jsp 里,如果 添加上 QiTaDianHua,如果为空就会报错,别的都么有问题null,或者是空格,或者是有数据 1. Stri ...