版权声明:本文为博主原创文章,未经博主同意不得转载。

https://blog.csdn.net/rlnLo2pNEfx9c/article/details/79648890

SparkStreaming与kafka010整合

读本文之前。请先阅读之前文章:

__biz=MzA3MDY0NTMxOQ==&mid=2247484551&idx=1&sn=ee51a406c1fa975489b7f9758a9e8d2c&chksm=9f38e7afa84f6eb934bc8bd09b106db456b4146a663d4bff759c0e2f9c0a03f30c7479ece62b&scene=21#wechat_redirect" rel="nofollow">必读:再讲Spark与kafka 0.8.2.1+整合

Spark Streaming与kafka 0.10的整合,和0.8版本号的direct Stream方式非常像。Kafka的分区和spark的分区是一一相应的,能够获取offsets和元数据。

API使用起来没有显著的差别。这个整合版本号标记为experimental。所以API有可能改变。

project依赖

首先,加入依赖。

groupId = org.apache.spark

artifactId = spark-streaming-kafka-0-10_2.11

version = 2.2.1

不要手动加入org.apache.kafka相关的依赖。如kafka-clients。

spark-streaming-kafka-0-10已经包括相关的依赖了,不同的版本号会有不同程度的不兼容。

代码案例

首先导入包正确的包org.apache.spark.streaming.kafka010

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
ssc = new StreamingContext(sparkConf, Milliseconds(1000))
val preferredHosts = LocationStrategies.PreferConsistent
val kafkaParams = Map[String, Object](
 "bootstrap.servers" -> "localhost:9092,anotherhost:9092",
 "key.deserializer" -> classOf[StringDeserializer],
 "value.deserializer" -> classOf[StringDeserializer],
 "group.id" -> "use_a_separate_group_id_for_each_stream",
 "auto.offset.reset" -> "latest",
 "enable.auto.commit" -> (false: java.lang.Boolean)
)

val topics = Array("topicA", "topicB")
val stream = KafkaUtils.createDirectStream[String, String](
 ssc,
 preferredHosts,
 Subscribe[String, String](topics, kafkaParams)
)

stream.map(record => (record.key, record.value))

kafka的參数,请參考kafka官网。假设。你的spark批次时间超过了kafka的心跳时间(30s),须要添加heartbeat.interval.ms和session.timeout.ms。比如。批处理时间是5min,那么就须要调整group.max.session.timeout.ms。注意。样例中是将enable.auto.commit设置为了false。

LocationStrategies(本地策略)

新版本号的消费者API会预取消息入buffer。

因此,为了提升性能,在Executor端缓存消费者(而不是每一个批次又一次创建)是非常有必要的,优先调度那些分区到已经有了合适消费者主机上。

在非常多情况下,你须要像上文一样使用LocationStrategies.PreferConsistent,这个參数会将分区尽量均匀地分配到全部的能够Executor上去。

假设。你的Executor和kafka broker在同一台机器上,能够用PreferBrokers。这将优先将分区调度到kafka分区leader所在的主机上。最后,分区间负荷有明显的倾斜,能够用PreferFixed。这个同意你指定一个明白的分区到主机的映射(没有指定的分区将会使用连续的地址)。

消费者缓存的数目默认最大值是64。假设你希望处理超过(64*excutor数目)kafka分区。spark.streaming.kafka.consumer.cache.maxCapacity这个參数能够帮助你改动这个值。

假设你想禁止kafka消费者缓存,能够将spark.streaming.kafka.consumer.cache.enabled改动为false。

禁止缓存缓存可能须要解决SPARK-19185描写叙述的问题。一旦这个bug解决。这个属性将会在后期的spark版本号中移除。

Cache是依照topicpartition和groupid进行分组的,所以每次调用creaDirectStream的时候要单独设置group.id。

ConsumerStrategies(消费策略)

新的kafka消费者api有多个不同的方法去指定消费者,当中有些方法须要考虑post-object-instantiation设置。

ConsumerStrategies提供了一个抽象,它同意spark能够获得正确配置的消费者。即使从Checkpoint重新启动之后。

ConsumerStrategies.Subscribe,如上面展示的一样,同意你订阅一组固定的集合的主题。

SubscribePattern同意你使用正则来指定自己感兴趣的主题。注意,跟0.8整合不同的是,使用subscribe或者subscribepattern在执行stream期间应相应到加入分区。

事实上,Assign执行你指定固定分区的集合。这三种策略都有重载构造函数。同意您指定特定分区的起始偏移量。

ConsumerStrategy是一个public类。同意你进行自己定义策略。

创建kafkaRDD

相似于spark streaming的批处理,如今你能够通过指定自己定义偏移范围自己创建kafkaRDD。

def getKafkaParams(extra: (String, Object)*): JHashMap[String, Object] = {
 val kp = new JHashMap[String, Object]()
 kp.put("bootstrap.servers", kafkaTestUtils.brokerAddress)
 kp.put("key.deserializer", classOf[StringDeserializer])
 kp.put("value.deserializer", classOf[StringDeserializer])
 kp.put("group.id", s"test-consumer-${Random.nextInt}-${System.currentTimeMillis}")
 extra.foreach(e => kp.put(e._1, e._2))
 kp
}

val kafkaParams = getKafkaParams("auto.offset.reset" -> "earliest")
// Import dependencies and create kafka params as in Create Direct Stream above

val offsetRanges = Array(
 // topic, partition, inclusive starting offset, exclusive ending offset
 OffsetRange("test", 0, 0, 100),
 OffsetRange("test", 1, 0, 100)
)

val rdd = KafkaUtils.createRDD[String, String](sparkContext, kafkaParams, offsetRanges, PreferConsistent)

注意。在这里是不能使用PreferBrokers的。由于不是流处理的话就没有driver端的消费者帮助你寻找元数据。必须使用PreferFixed,然后自己指定元数据

大家能够进入createRDD里面。看其源代码。事实上就是依据你的參数封装成了RDD,跟流式批处理是一致的。

def createRDD[K, V](
   sc: SparkContext,
   kafkaParams: ju.Map[String, Object],
   offsetRanges: Array[OffsetRange],
   locationStrategy: LocationStrategy
 ): RDD[ConsumerRecord[K, V]] = {
 val preferredHosts = locationStrategy match {
   case PreferBrokers =>
     throw new AssertionError(
       "If you want to prefer brokers, you must provide a mapping using PreferFixed " +
       "A single KafkaRDD does not have a driver consumer and cannot look up brokers for you.")
   case PreferConsistent => ju.Collections.emptyMap[TopicPartition, String]()
   case PreferFixed(hostMap) => hostMap
 }
 val kp = new ju.HashMap[String, Object](kafkaParams)
 fixKafkaParams(kp)
 val osr = offsetRanges.clone()

 new KafkaRDD[K, V](sc, kp, osr, preferredHosts, true)
}

获取偏移

Spark Streaming与kafka整合是执行你获取其消费的偏移的,详细方法例如以下:

stream.foreachRDD { rdd =>
 val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
 rdd.foreachPartition { iter =>
   val o: OffsetRange = offsetRanges(TaskContext.get.partitionId)
   println(s"${o.topic} ${o.partition} ${o.fromOffset} ${o.untilOffset}")
 }
}

注意。HashOffsetRanges只在spark计算链条的開始才干类型转换成功。要知道kafka分区和spark分区的一一相应关系在Shuffle后就会丧失,比方reduceByKey()或者window()。

存储偏移

Kafka在有可能存在任务失败的情况下的从消息传输语义(至少一次。最多一次,恰好一次)是取决于何时存储offset。Spark输出操作是至少一次传输语义。所以,假设你想实现只一次的消费语义,你必须要么在密等输出后存储offset,要么就是offset的存储和结果输出是一次事务。

如今kafka有了3种方式,来提高可靠性(以及代码复杂性),用于存储偏移量。

1, Checkpoint

假设使能了Checkpoint,offset被存储到Checkpoint。

这个尽管非常easy做到,可是也有一些缺点。由于会多次输出结果,所以结果输出必须是满足幂等性。

同一时候事务性不可选。另外,假设代码变更,你是不能够从Checkpoint恢复的。针对代码升级更新操作,你能够同一时候执行你的新任务和旧任务(由于你的输出结果是幂等性)。对于以外的故障,而且同一时候代码变更了,肯定会丢失数据的,除非另有方式来识别启动消费的偏移。

2。 Kafka自身

Kafka提供的有api。能够将offset提交到指定的kafkatopic。默认情况下,新的消费者会周期性的自己主动提交offset到kafka。可是有些情况下,这也会有些问题,由于消息可能已经被消费者从kafka拉去出来。可是spark还没处理,这样的情况下会导致一些错误。

这也是为什么样例中stream将enable.auto.commit设置为了false。

然而在已经提交spark输出结果之后。你能够手动提交偏移到kafka。

相对于Checkpoint,offset存储到kafka的优点是:kafka既是一个容错的存储系统,也是能够避免代码变更带来的麻烦。提交offset到kafka和结果输出也不是一次事务,所以也要求你的输出结果是满足幂等性。

stream.foreachRDD { rdd =>
 val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges

 // some time later, after outputs have completed
 stream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)
}

由于带有HasOffsetRanges。到CanCommitOffsets的转换将会在刚执行createDirectStream之后成功,而不是经过各种操作算子后。

commitAsync是线程安全的。必须在结果提交后进行执行。

3。 自己定义存储位置

对于输出解雇支持事务的情况,能够将offset和输出结果在同一个事务内部提交,这样即使在失败的情况下也能够保证两者同步。

假设您关心检測反复或跳过的偏移范围。回滚事务能够防止反复或丢失的消息。

这相当于一次语义。也能够使用这样的策略,甚至是聚合所产生的输出,聚合产生的输出一般是非常难生成幂等的。代码演示样例

// The details depend on your data store, but the general idea looks like this

// begin from the the offsets committed to the database
val fromOffsets = selectOffsetsFromYourDatabase.map { resultSet =>
 new TopicPartition(resultSet.string("topic"), resultSet.int("partition")) -> resultSet.long("offset")
}.toMap

val stream = KafkaUtils.createDirectStream[String, String](
 streamingContext,
 PreferConsistent,
 Assign[String, String](fromOffsets.keys.toList, kafkaParams, fromOffsets)
)

stream.foreachRDD { rdd =>
 val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges

 val results = yourCalculation(rdd)

 // begin your transaction

 // update results
 // update offsets where the end of existing offsets matches the beginning of this batch of offsets
 // assert that offsets were updated correctly

 // end your transaction
}

SSL/TLS配置使用

新的kafka消费者支持SSL。只须要在执行createDirectStream / createRDD之前设置kafkaParams。

注意。这只应用与Spark和kafkabroker之间的通讯。仍然负责分别确保节点间通信的安全。

val kafkaParams = Map[String, Object](
 // the usual params, make sure to change the port in bootstrap.servers if 9092 is not TLS
 "security.protocol" -> "SSL",
 "ssl.truststore.location" -> "/some-directory/kafka.client.truststore.jks",
 "ssl.truststore.password" -> "test1234",
 "ssl.keystore.location" -> "/some-directory/kafka.client.keystore.jks",
 "ssl.keystore.password" -> "test1234",
 "ssl.key.password" -> "test1234"
)

Spark相关书籍,请进入浪尖微店。

推荐阅读:

1。Hdfs的数据磁盘大小不均衡怎样处理

2。数据科学的工作流程

3,

__biz=MzA3MDY0NTMxOQ==&mid=2247483792&idx=1&sn=2fe2364e08fec3fd9d57d2f5d1b99e2b&chksm=9f38e2b8a84f6baee19e8d430e522389cf8df33820d95dbfa4f0e4ef63f7661ca3bf41e73d7f&scene=21#wechat_redirect" rel="nofollow">大数据基础系列之spark的监控体系介绍

4,金融反欺诈场景下的Spark实践

wx_fmt=png" alt="640?wx_fmt=png" />

必读:Spark与kafka010整合的更多相关文章

  1. spark第十篇:Spark与Kafka整合

    spark与kafka整合需要引入spark-streaming-kafka.jar,该jar根据kafka版本有2个分支,分别是spark-streaming-kafka-0-8和spark-str ...

  2. Spark Streaming + Kafka 整合向导之createDirectStream

    启动zk: zkServer.sh start 启动kafka:kafka-server-start.sh $KAFKA_HOME/config/server.properties 创建一个topic ...

  3. Spark Streaming + Kafka整合(Kafka broker版本0.8.2.1+)

    这篇博客是基于Spark Streaming整合Kafka-0.8.2.1官方文档. 本文主要讲解了Spark Streaming如何从Kafka接收数据.Spark Streaming从Kafka接 ...

  4. spark与flume整合

    spark-streaming与flume整合  push package cn.my.sparkStream import org.apache.spark.SparkConf import org ...

  5. Spark之 SparkSql整合hive

    整合: 1,需要将hive-site.xml文件拷贝到Spark的conf目录下,这样就可以通过这个配置文件找到Hive的元数据以及数据存放位置. 2,如果Hive的元数据存放在Mysql中,我们还需 ...

  6. Hadoop+Spark+Hbase部署整合篇

    之前的几篇博客中记录的Hadoop.Spark和Hbase部署过程虽然看起来是没多大问题,但是之后在上面跑任务的时候出现了各种各样的配置问题.庆幸有将问题记录下来,可以整理出这篇部署整合篇. 确保集群 ...

  7. Zookeeper+Kafka+Spark streaming单机整合开发

    环境准备: ubuntu 开发环境: jdk 1.8 scala:2.11.0 spark 2.0 zookeeper 3.4.6 kafka  2.12-0.10.2.0 开始整合: 1 zooke ...

  8. Spark 实时计算整合案例

    1.概述 最近有同学问道,除了使用 Storm 充当实时计算的模型外,还有木有其他的方式来实现实时计算的业务.了解到,在使用 Storm 时,需要编写基于编程语言的代码.比如,要实现一个流水指标的统计 ...

  9. Spark Streaming + Flume整合官网文档阅读及运行示例

    1,基于Flume的Push模式(Flume-style Push-based Approach)      Flume被用于在Flume agents之间推送数据.在这种方式下,Spark Stre ...

随机推荐

  1. [ONTAK2015]OR-XOR

    [ONTAK2015]OR-XOR 题目大意: 一个长度为\(n(n\le5\times10^5)\)的序列\(A(0\le A_i\le10^{18})\),将其分为恰好\(m\)个连续段,设每一段 ...

  2. [QTree6]Query on a tree VI

    Description: 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括 ...

  3. python3.6.5 + selenium +VS Code 运行报错:Unable to find a matching set of capabilities的解决

    在python3.6.5 + selenium +VS Code 环境中,在class的__init__ 方法初始化火狐浏览器时出现以下错误: 发生异常: selenium.common.except ...

  4. the lime limited error

    转载自:https://blog.csdn.net/MTOY_320/article/details/78363375?locationNum=7&fps=1 经常会遇到这种令人抓狂的情况 自 ...

  5. 使用git(window)在github上存项目教程

    要托管到github,那你就应该要有一个属于你自己的github帐号,所以你应该先到github.com注册 打开浏览器 在地址栏输入地址:github.com 填写用户名.邮箱.密码 点击Sign ...

  6. windbg foreach用法

    .foreach 关键字分析一个或多个命令的输出并将该输出中每一个值作为另一个或多个命令的输入 .foreach [Options] ( Variable  { InCommands } ) { Ou ...

  7. yii2 用 bootstrap 给元素添加背景色

    使用 bootstrap 给元素添加背景色 1.bootstrap 官网:http://getbootstrap.com/ 2.bootstrap 中文官网:http://v3.bootcss.com ...

  8. Yii2 数据搜索类 PostSearch

    数据搜索类 PostSearch /** * @Purpose : 添加 authorName 属性,使属性和搜索表单相对应 * @return array */ public function at ...

  9. Java基础知识总结--反射

    反射:在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每一个对象所属的类.虚拟机利用运行时类型信息选择相应的方法执行. Java反射机制是在系统运行状态 ...

  10. Vue(二十)项目初始化步骤

    提:需要安装 node.js / npm淘宝镜像 / webpack / vue-cli脚手架构建工具 1.创建项目 - vue init webpack framework https://gith ...