推荐系统的在线部分往往使用spark-streaming实现,这是一个很重要的环节。

在线流程的实时数据一般是从kafka获取消息到spark streaming

spark连接kafka两种方式在面试中会经常被问到,说明这是重点,下面为大家介绍一下这两种方法:

第一种方式:Receiver模式 又称kafka高级api模式

效果:SparkStreaming中的Receivers,恰好kafka有发布、订阅,然而:这种方式企业不常用,说明有bug,不符合企业需求。因为:接收到的数据存储在Executor,会出现数据漏处理或者多处理状况。

简单的理解就是kafka把消息全部封装好,提供给spark去调用,本来kafka的消息分布在不同的partition上面,相当于做了一步数据合并,在发送给spark,故spark可以设置executor个数去消费这部分数据,效率相对慢一些。

代码实例:

object ReceiverKafkaWordCount {
Logger.getLogger("org").setLevel(Level.ERROR)
def main(args: Array[String]): Unit = {
val Array(brokers, topics) = Array(Conf.KAFKA_BROKER, Conf.TEST_TOPIC)
// Create context with 2 second batch interval
val conf = new SparkConf()
.setMaster("local")
.setAppName("OnlineStreamHobby") //设置本程序名称
// .set("auto.offset.reset","smallest")
val ssc = new StreamingContext(conf, Seconds(2))
// 从kafka取数据
val kafkaParams: Map[String, String] = Map[String, String](
// "auto.offset.reset" -> "smallest", //自动将偏移重置为最早的偏移
"zookeeper.connect" -> Conf.ZK_HOST,
// "bootstrap.servers" -> Common.KAFKA_BROKER_LIST,
"group.id" -> "test"
)
val numThreads = 1
val topicMap = topics.split(",").map((_, numThreads.toInt)).toMap
val fact_streaming = KafkaUtils.createStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, topicMap, StorageLevel.MEMORY_AND_DISK_2).map(_._2)
// fact_streaming.print()
val words = fact_streaming.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1L)).reduceByKey(_ + _)
wordCounts.print()
ssc.checkpoint(".")
//启动spark并设置执行时间
ssc.start()
ssc.awaitTermination()
}
}

第二种方式:Direct模式 又称kafka低级API模式

效果:每次到topic的每个partition依据偏移量进行获取数据,拉取数据以后进行处理,可以实现高可用

解释:在spark 1.3中引入了这种新的无接收器“直接”方法,以确保更强大的端到端保证。这种方法不是使用接收器来接收数据,而是定期查询kafka在每个topic+分partition中的最新偏移量,并相应地定义要在每个批次中处理的偏移量范围。当处理数据的作业启动时,Kafka简单的客户API用于读取Kafka中定义的偏移范围(类似于从文件系统读取文件)。请注意,此功能在Spark 1.3中为Scala和Java API引入

简单的理解就是spark直接从kafka底层中的partition直接获取消息,相对于Receiver模式少了一步,效率更快。但是这样一来spark中的executor的工作的个数就为kafka中的partition一致,设置再多的executor都不工作,同时偏移量也需要自己维护。

代码示例:

object DirectTest {
def main(args: Array[String]) {
val conf = new SparkConf().setAppName("kafka direct test").setMaster("local")
val sc = new SparkContext(conf)
val ssc = new StreamingContext(sc,Seconds(10))
//kafka基本参数,yourBrokers你的brokers集群
val kafkaParams = Map("metadata.broker.list" -> Conf.KAFKA_BROKER)
val topic = "test"
val customGroup = "testGroup"
//新建一个zkClient,zk是你的zk集群,和broker一样,也是"IP:端口,IP端口..."
/**
*如果你使用val zkClient = new ZKClient(zk)新建zk客户端,
*在后边读取分区信息的文件数据时可能会出现错误
*org.I0Itec.zkclient.exception.ZkMarshallingError:
* java.io.StreamCorruptedException: invalid stream header: 7B226A6D at org.I0Itec.zkclient.serialize.SerializableSerializer.deserialize(SerializableSerializer.java:37) at org.I0Itec.zkclient.ZkClient.derializable(ZkClient.java:740) ..
*那么使用我的这个新建方法就可以了,指定读取数据时的序列化方式
**/
val zkClient = new ZkClient(Conf.ZK_HOST, Integer.MAX_VALUE, 10000,ZKStringSerializer)
//获取zk下该消费者的offset存储路径,一般该路径是/consumers/test_spark_streaming_group/offsets/topic_name
val topicDirs = new ZKGroupTopicDirs(customGroup, topic)
val children = zkClient.countChildren(s"${topicDirs.consumerOffsetDir}")
//设置第一批数据读取的起始位置
var fromOffsets: Map[TopicAndPartition, Long] = Map()
var directKafkaStream : InputDStream[(String,String)] = null
//如果zk下有该消费者的offset信息,则从zk下保存的offset位置开始读取,否则从最新的数据开始读取(受auto.offset.reset设置影响,此处默认)
if (children > 0) {
//将zk下保存的该主题该消费者的每个分区的offset值添加到fromOffsets中
for (i <- 0 until children) {
val partitionOffset = zkClient.readData[String](s"${topicDirs.consumerOffsetDir}/$i")
val tp = TopicAndPartition(topic, i)
//将不同 partition 对应的 offset 增加到 fromOffsets 中
fromOffsets += (tp -> partitionOffset.toLong)
println("@@@@@@ topic[" + topic + "] partition[" + i + "] offset[" + partitionOffset + "] @@@@@@")
val messageHandler = (mmd: MessageAndMetadata[String, String]) => (mmd.topic,mmd.message())
directKafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder, (String,String)](ssc, kafkaParams, fromOffsets, messageHandler)
}
}else{
directKafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, Set(topic))
}
/**
*上边已经实现从zk上保存的值开始读取数据
*下边就是数据处理后,再讲offset值写会到zk上
*/
//用于保存当前offset范围
var offsetRanges: Array[OffsetRange] = Array.empty
val directKafkaStream1 = directKafkaStream.transform { rdd =>
//取出该批数据的offset值
offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
rdd
}.map(_._2)
directKafkaStream1.foreachRDD(rdd=>{
//数据处理完毕后,将offset值更新到zk集群
for (o <- offsetRanges) {
val zkPath = s"${topicDirs.consumerOffsetDir}/${o.partition}"
ZkUtils.updatePersistentPath(zkClient, zkPath, o.fromOffset.toString)
}
rdd.foreach(println)
})
ssc.start()
ssc.awaitTermination()
}
}

spark-streaming-连接kafka的两种方式的更多相关文章

  1. Spark Streaming连接Kafka的两种方式 direct 跟receiver 方式接收数据的区别

    Receiver是使用Kafka的高层次Consumer API来实现的. Receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming ...

  2. Spark Streaming 交互 Kafka的两种方式

    一.Spark Streaming连Kafka(重点) 方式一:Receiver方式连:走磁盘 使用High Level API(高阶API)实现Offset自动管理,灵活性差,处理数据时,如果某一时 ...

  3. sparkStreaming读取kafka的两种方式

    概述 Spark Streaming 支持多种实时输入源数据的读取,其中包括Kafka.flume.socket流等等.除了Kafka以外的实时输入源,由于我们的业务场景没有涉及,在此将不会讨论.本篇 ...

  4. ADB连接手机的两种方式(usb数据线连接和wifi连接)

    ADB(Android Debug Bridge)安卓测试桥,它是连接电脑开发端和安卓设备的桥梁,这个安卓设备可以是真实的安卓手机或者平板,也可以是虚拟的安卓模拟器,   这里介绍ADB连接手机的两种 ...

  5. 利用adb查看手机设备ip和连接手机的两种方式

    电脑安装adb(查看菜鸟adb教程) [cmd]->输入adb devices (设置了path,否则需要 ./路径/adb devices)如图: 查看ip两种方法(可能有更多,目前我还没看到 ...

  6. spark streaming集成kafka接收数据的方式

    spark streaming是以batch的方式来消费,strom是准实时一条一条的消费.当然也可以使用trident和tick的方式来实现batch消费(官方叫做mini batch).效率嘛,有 ...

  7. 网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别

    1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2 ...

  8. spark application提交应用的两种方式

    bin/spark-submit --help ... ... --deploy-mode DEPLOY_MODE   Whether to launch the driver program loc ...

  9. adb连接手机的两种方式

    adb连接手机进行调试有两种方式,一种使用USB线,一种使用无线WiFi. 第一种  使用USB线连接 1. 在手机上启用USB调试 2. CMD窗口输入adb devices,此时可以看到自己的设备 ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:布局控件layout的LeftMargin等contentsMargins属性

    在Qt Designer中布局控件有4个,分别是Vertical Layout(垂直布局).Horizontal Layout(水平布局).Grid Layout(网格布局).Form Layout( ...

  2. PHP代码审计分段讲解(5)

    11 sql闭合绕过 源代码为 <?php if($_POST[user] && $_POST[pass]) { $conn = mysql_connect("**** ...

  3. Day1 【Scrum 冲刺博客】

    (因发作业当天没注意看作业内容,第一天的冲刺博客和第二天的同时发!!!不好意思!!!) 各个成员在 Alpha 阶段认领的任务 方晓莹 搭建社区管理系统的前端框架 登录页开发 管理员模块个人中心开发 ...

  4. 团队作业3_需求改进&系统设计

    一.需求&原型改进 1.需求改进: (1)发现问题:通过发布问卷调查及收集整理的形式发现用户的新需求: (2)修改需求:考虑新增提醒用户未完成事件的功能.   附:用户调查问卷(如下) 调研途 ...

  5. Java集合源码分析(一)——集合框架

    集合框架 集合框架如图所示 Java集合是Java提供的工具包,主要包括常用的数据结构,包括:集合.链表.队列.栈.数组.映射等. 集合的工具包位置是java.util.* 集合主要可以分为五类: L ...

  6. spark有个节点特别慢,解决办法

    除解决数据倾斜问题外,还要开启推测执行,寻找另一个executor执行task,哪个先完成就取哪个结果,再kill掉另一个.

  7. NameSilo的DDNS动态域名解析

    用Java写的,一个实时检测IP变化并更新DNS状态的工具,适用于在NameSilo购买的域名,如果你的域名是在其他商家购买的,修改为你自己的api就行.代码我放github了,地址: https:/ ...

  8. logstash导入DNS解析数据到es中,中间有filebeat

    这个过程中,主要用logstash处理数据的时候不好处理. 在logstash-sample.conf这个配置文件中的配置,我用这个监控filebeat的5044端口 # Sample Logstas ...

  9. 云小课 | 需求任务还未分解,该咋整!项目管理Scrum项目工作分解的心酸谁能知?

    温馨提醒:本文约3000字,需要阅读5分钟,共分为8个部分,建议分段阅读! 软件开发过程中,从产品概念形成到产品规划.往往要做详细的需求分析和项目规划等,因此,选对一款项目管理工具对开发者就显得尤为重 ...

  10. writeset参数配置探索——究竟在哪个角色上配置参数?

    关于writeset,一直以来我都是所有节点同时配置下面参数: binlog_transaction_dependency_tracking=WRITESET transaction_write_se ...