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

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. mysql复习

    1.数据库操作 CREATE DATABASE 数据库名 charset utf8; 查看数据库 show databases; show create database db1; select da ...

  2. 简单酷炫的Canvas数字时钟

    声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 我记得很早之前就看过这个DEMO,是岑安大大博客里看到的: 就是这个数字时钟,当时觉得这个创意不错,但是也没去折腾.直到昨天同事又在网上看 ...

  3. 安装并运行Hello World

    新建虚拟环境并安装Flask pip install Flask 运行HelloWorld from flask import Flask #导入Flask类 app = Flask(__name__ ...

  4. Centos服务器端口无法访问

    使用GPRS A6 模块进行TCP连接的时候,一度认为A6模块坏掉了 最终只是服务器端口都被防火墙堵住了 使用之前一直用的  service iptables stop  找不到iptables 原来 ...

  5. GMA Round 1 双曲线与面积

    传送门 双曲线与面积 P是双曲线$\frac{x^2}{1471^2}-\frac{y^2}{1372^2}=1$上的一个动点,现在过P作一条直线与该双曲线的两条渐近线相交于A.B两点,且|AP|=| ...

  6. Uva11582 Colossal Fibonacci Numbers!(同余模定理+快速幂)

    https://vjudge.net/problem/UVA-11582 首先明确,斐波那契数列在模c的前提下是有循环节的.而f[i] = f[i-1]+f[i-2](i>=2)所以只要有两个连 ...

  7. IDEA下Maven的Offline Mode

    今天上午别人加了一个Maven依赖项(dependency)我始终获取不到本地 Maven的setting.xml文件检查没有问题 根目录的pom.xml检查也没有问题 本来怀疑公司的Maven服务器 ...

  8. 对Unity的Resources目录进行改名

    项目用的是Unity5.5版本,开发的时候将相关的图集.预制对象资源都放在 Resources 目录下,而真机使用的是 StreamingAssets 目录下的资源. Resources(不分层级)在 ...

  9. php 通过 create user 和grant 命令无法创建数据库用户和授权的解决办法

    php 通过 create user 和grant 命令无法创建数据库用户和授权的解决办法 解决办法, 通过 insert 命令的方式进行创建. 创建数据库用户: $sql= "insert ...

  10. gtest环境安装

    gtest全称Google Test,是Google的C++测试框架,有很多优秀的软件都会依赖这个环境编译或者在开发中也会用到,gtest的编译非常简单,下面简单说明一下安装过程. gtest git ...