4、spark streaming+kafka
一、Receiver模式
1、 receiver模式原理图
在SparkStreaming程序运行起来后,Executor中会有receiver tasks接收kafka推送过来的数据。数据会被持久化,默认级别为MEMORY_AND_DISK_SER_2,这个级别也
可以修改。receiver task对接收过来的数据进行存储和备份,这个过程会有节点之间的数据传输。备份完成后去zookeeper中更新消费偏移量,然后向Driver中的
receiver tracker汇报数据的位置。最后Driver根据数据本地化将task分发到不同节点上执行。
2、receiver模式中存在的问题及解决
当Driver进程挂掉后,Driver下的Executor都会被杀掉,当更新完zookeeper消费偏移量的时候,Driver如果挂掉了,就会存在找不到数据的问题,相当于丢失数据。 如何解决这个问题?
开启WAL(write ahead log)预写日志机制,在接受过来数据备份到其他节点的时候,同时备份到HDFS上一份(我们需要将接收来的数据的持久化级别降级到MEMORY_AND_DISK),
这样就能保证数据的安全性。不过,因为写HDFS比较消耗性能,要在备份完数据之后才能进行更新zookeeper以及汇报位置等,这样会增加job的执行时间,这样对于任务的
执行提高了延迟度。
3、receiver模式描述
1.kafka有两种消费者api:
1.High Level Consumer APl消费者不能做到自己去维护消费者offset,使用高级api时,不关心数据丢失。
kafka+SparkStreaming Receiver模式就是High Level Consumer API实现的。
2.Simple Consumer APl消费者可以自己管理offset. 2.过程:
kafka+SparkStreaming receiver 模式接受数据,当向zookeeper中更新完offset后,Driver如果挂掉,Driver 下的Executor 会被kill,会造成丢失数据。 怎么解决?
开启WAL(Write Ahead Log)预写日志机利,将数据备份到HDFS中一份,再去更新zookeeper offset,如果开启了WAL机利,接收数据的存储级别要降级,
去掉"2”开启WAL机利会加大application处理的时间。 3.receiver模式依赖zookeeper管理offset. 4.receiver模式的并行度?由spark.streaming.blockInterval=200ms决定。
receiver 模式接受数据时,每隔spark.streaming.blockInterval将数据落地一个block,假设batchlnterval=5s,一个batch内生成25个block。
batch-block,batch封装到RDD中,RDD-partition,这里的block对应的就是RDD中的partition。 如何提高receiver模式的并行度?
在batchlnterval一定情况下,减少spark.streaming.blocklnterval 参数值,增大生成的DStream中RDD的partition个数,
但是建议spark.streaming.blocklnterval最低不能低于50ms.
3、Receive模式Wordcount案例
package cn.spark.study.streaming; import java.util.Arrays;
import java.util.HashMap;
import java.util.Map; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaPairReceiverInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka.KafkaUtils; import scala.Tuple2; /**
* 基于Kafka receiver方式的实时wordcount程序
* @author Administrator
*
*/
public class KafkaReceiverWordCount { public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setMaster("local[2]")
.setAppName("KafkaWordCount");
JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5)); // 使用KafkaUtils.createStream()方法,创建针对Kafka的输入数据流
Map<String, Integer> topicThreadMap = new HashMap<String, Integer>();
// 使用多少个线程去拉取topic的数据
topicThreadMap.put("WordCount", 1); // 这里接收的四个参数;第一个:streamingContext
// 第二个:ZK quorum; 第三个:consumer group id 可以自己写;
// 第四个:per-topic number of Kafka partitions to consume
JavaPairReceiverInputDStream<String, String> lines = KafkaUtils.createStream(
jssc,
"192.168.1.135:2181,192.168.1.136:2181,192.168.1.137:2181",
"DefaultConsumerGroup",
topicThreadMap); // wordcount逻辑
JavaDStream<String> words = lines.flatMap( new FlatMapFunction<Tuple2<String,String>, String>() { private static final long serialVersionUID = 1L; @Override
public Iterable<String> call(Tuple2<String, String> tuple)
throws Exception {
return Arrays.asList(tuple._2.split(" "));
} }); JavaPairDStream<String, Integer> pairs = words.mapToPair( new PairFunction<String, String, Integer>() { private static final long serialVersionUID = 1L; @Override
public Tuple2<String, Integer> call(String word)
throws Exception {
return new Tuple2<String, Integer>(word, 1);
} }); JavaPairDStream<String, Integer> wordCounts = pairs.reduceByKey( new Function2<Integer, Integer, Integer>() { private static final long serialVersionUID = 1L; @Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
} }); wordCounts.print(); jssc.start();
jssc.awaitTermination();
jssc.close();
} } ##eclipse中运行程序 ##新建一个topic
[root@spark1 kafka]# bin/kafka-topics.sh --zookeeper 192.168.1.135:2181,192.168.1.136:2181,192.168.1.137:2181 --topic WordCount --replication-factor 1 --partitions 1 --create ##启动生产者,然后可以输入一些数据,观察程序端的输出统计
[root@spark1 kafka]# bin/kafka-console-producer.sh --broker-list 192.168.1.135:9092,192.168.1.136:9092,192.168.1.137:9092 --topic WordCount
二、Driect模式
1、driect模式原理图
2、Direct模式理解
Direct 模式采用的是kafka的Simple Consumer APl。 Driect模式就是将kafka看成存数据的一方,不是被动接收数据,而是主动去取数据。消费者偏移量也不是用zookeeper来管理,而是SparkStreaming内部对消费者
偏移量自动来维护,默认消费偏移量是在内存中,当然如果设置了checkpoint目录,那么消费偏移量也会保存在checkpoint中。当然也可以实现用zookeeper来管理。 Direct模式生成的DStream中的RDD的并行度是与读取的topic中的partition个数一致。
Direct模式最好指定checkpoint
3、Direct模式Wordcount案例
package cn.spark.study.streaming; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; import kafka.serializer.StringDecoder; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaPairInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka.KafkaUtils; import scala.Tuple2; /**
* 基于Kafka Direct方式的实时wordcount程序
* @author Administrator
*
*/
public class KafkaDirectWordCount { public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setMaster("local[2]")
.setAppName("KafkaDirectWordCount");
JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5)); // 首先,要创建一份kafka参数map
Map<String, String> kafkaParams = new HashMap<String, String>();
kafkaParams.put("metadata.broker.list",
"192.168.1.135:9092,192.168.1.136:9092,192.168.1.137:9092"); // 然后,要创建一个set,里面放入,你要读取的topic
// 这个,就是我们所说的,它自己给你做的很好,可以并行读取多个topic
Set<String> topics = new HashSet<String>();
topics.add("WordCount"); // 创建输入DStream
JavaPairInputDStream<String, String> lines = KafkaUtils.createDirectStream(
jssc,
String.class,
String.class,
StringDecoder.class,
StringDecoder.class,
kafkaParams,
topics); // 执行wordcount操作
JavaDStream<String> words = lines.flatMap( new FlatMapFunction<Tuple2<String,String>, String>() { private static final long serialVersionUID = 1L; @Override
public Iterable<String> call(Tuple2<String, String> tuple)
throws Exception {
return Arrays.asList(tuple._2.split(" "));
} }); JavaPairDStream<String, Integer> pairs = words.mapToPair( new PairFunction<String, String, Integer>() { private static final long serialVersionUID = 1L; @Override
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
} }); JavaPairDStream<String, Integer> wordCounts = pairs.reduceByKey( new Function2<Integer, Integer, Integer>() { private static final long serialVersionUID = 1L; @Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
} }); wordCounts.print(); jssc.start();
jssc.awaitTermination();
jssc.close();
} } ##检查运行,和receive模式类似
三、手动管理offset
1、手动管理offset
在zookeeper中自己管理offset; 使用mysql管理; 使用HBase管理;
2、代码
package com.manage; import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import com.google.common.collect.ImmutableMap;
import com.manage.getOffset.GetTopicOffsetFromKafkaBroker;
import com.manage.getOffset.GetTopicOffsetFromZookeeper; import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryUntilElapsed;
import org.apache.log4j.Logger;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaInputDStream;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.api.java.JavaStreamingContextFactory;
import org.apache.spark.streaming.kafka.HasOffsetRanges;
import org.apache.spark.streaming.kafka.KafkaUtils;
import org.apache.spark.streaming.kafka.OffsetRange;
import kafka.cluster.Broker; import com.fasterxml.jackson.databind.ObjectMapper; import kafka.api.PartitionOffsetRequestInfo;
import kafka.common.TopicAndPartition;
import kafka.javaapi.OffsetRequest;
import kafka.javaapi.OffsetResponse;
import kafka.javaapi.PartitionMetadata;
import kafka.javaapi.TopicMetadata;
import kafka.javaapi.TopicMetadataRequest;
import kafka.javaapi.TopicMetadataResponse;
import kafka.javaapi.consumer.SimpleConsumer;
import kafka.message.MessageAndMetadata;
import kafka.serializer.StringDecoder;
import scala.Tuple2; public class UseZookeeperManageOffset {
/**
* 使用log4j打印日志,“UseZookeeper.class” 设置日志的产生类
*/
static final Logger logger = Logger.getLogger(UseZookeeperManageOffset.class); public static void main(String[] args) {
/**
* 加载log4j的配置文件,方便打印日志
*/
ProjectUtil.LoadLogConfig();
logger.info("project is starting..."); /**
* 从kafka集群中得到topic每个分区中生产消息的最大偏移量位置
*/
Map<TopicAndPartition, Long> topicOffsets = GetTopicOffsetFromKafkaBroker.getTopicOffsets("node1:9092,node2:9092,node3:9092", "mytopic"); /**
* 从zookeeper中获取当前topic每个分区 consumer 消费的offset位置
*/
Map<TopicAndPartition, Long> consumerOffsets =
GetTopicOffsetFromZookeeper.getConsumerOffsets("node3:2181,node4:2181,node5:2181","zhy","mytopic"); /**
* 合并以上得到的两个offset ,
* 思路是:
* 如果zookeeper中读取到consumer的消费者偏移量,那么就zookeeper中当前的offset为准。
* 否则,如果在zookeeper中读取不到当前消费者组消费当前topic的offset,就是当前消费者组第一次消费当前的topic,
* offset设置为topic中消息的最大位置。
*/
if(null!=consumerOffsets && consumerOffsets.size()>0){
topicOffsets.putAll(consumerOffsets);
}
/**
* 如果将下面的代码解开,是将topicOffset 中当前topic对应的每个partition中消费的消息设置为0,就是从头开始。
*/
// for(Map.Entry<TopicAndPartition, Long> item:topicOffsets.entrySet()){
// item.setValue(0l);
// } /**
* 构建SparkStreaming程序,从当前的offset消费消息
*/
JavaStreamingContext jsc = SparkStreamingDirect.getStreamingContext(topicOffsets,"zhy");
jsc.start();
jsc.awaitTermination();
jsc.close(); }
}
package com.manage; import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator; public class ProjectUtil {
/**
* 使用log4j配置打印日志
*/
static final Logger logger = Logger.getLogger(UseZookeeperManageOffset.class);
/**
* 加载配置的log4j.properties,默认读取的路径在src下,如果将log4j.properties放在别的路径中要手动加载
*/
public static void LoadLogConfig() {
PropertyConfigurator.configure("d:/eclipse4.7WS/SparkStreaming_Kafka_Manage/resource/log4j.properties");
} /**
* 加载配置文件
* 需要将放config.properties的目录设置成资源目录
* @return
*/
public static Properties loadProperties() { Properties props = new Properties();
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties");
if(null != inputStream) {
try {
props.load(inputStream);
} catch (IOException e) {
logger.error(String.format("Config.properties file not found in the classpath"));
}
}
return props; } public static void main(String[] args) {
Properties props = loadProperties();
String value = props.getProperty("hello");
System.out.println(value);
}
}
4、spark streaming+kafka的更多相关文章
- 160728、Spark Streaming kafka 实现数据零丢失的几种方式
定义 问题开始之前先解释下流处理中的一些概念: At most once - 每条数据最多被处理一次(0次或1次) At least once - 每条数据最少被处理一次 (1次或更多) Exactl ...
- 53、Spark Streaming:输入DStream之Kafka数据源实战
一.基于Receiver的方式 1.概述 基于Receiver的方式: Receiver是使用Kafka的高层次Consumer API来实现的.receiver从Kafka中获取的数据都是存储在Sp ...
- Spark streaming + Kafka 流式数据处理,结果存储至MongoDB、Solr、Neo4j(自用)
KafkaStreaming.scala文件 import kafka.serializer.StringDecoder import org.apache.spark.SparkConf impor ...
- Spark踩坑记——Spark Streaming+Kafka
[TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...
- Spark Streaming+Kafka
Spark Streaming+Kafka 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端, ...
- Spark Streaming + Kafka整合(Kafka broker版本0.8.2.1+)
这篇博客是基于Spark Streaming整合Kafka-0.8.2.1官方文档. 本文主要讲解了Spark Streaming如何从Kafka接收数据.Spark Streaming从Kafka接 ...
- Spark踩坑记:Spark Streaming+kafka应用及调优
前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从k ...
- 62、Spark Streaming:容错机制以及事务语义
一. 容错机制 1.背景 要理解Spark Streaming提供的容错机制,先回忆一下Spark RDD的基础容错语义: 1.RDD,Ressilient Distributed Dataset,是 ...
- 61、Spark Streaming:部署、升级和监控应用程序
一.部署应用程序 1.流程 1.有一个集群资源管理器,比如standalone模式下的Spark集群,Yarn模式下的Yarn集群等. 2.打包应用程序为一个jar包. 3.为executor配置充足 ...
随机推荐
- texlive2019安装
TeX Live 是 TUG (TeX User Group) 发布并维护的的 TeX 系统,可以称得上是TeX的官方系统,官网为:https://www.tug.org/texlive/ 1.通过最 ...
- Linux 7 重置root密码
在运维工作中经常会遇到不知道密码,密码遗忘,密码被他人修改过的情况,使用这种方式扫清你一切烦恼! 1.启动Linux系统,在出现引导界面时,按“e”键,进入内核编辑界面:2.找到有“linux16”的 ...
- 07、MySQL—时间日期类型
时间日期类型 1.Date 日期类型:系统使用三个字节来存储数据,对应的格式为:YYYY-mm-dd,能表示的范围是从1000-01-01 到9999-12-12,初始值为0000-00-00 2.T ...
- TCP三次握手四次挥手介绍
学过计算机网络的同学都知道TCP协议是计算机网络课程里面最复杂的协议之一,还没有通信就要搞个什么三次握手,断开还要什么四次分手,中间还要什么流量控制啦,拥塞控制,滑动窗口什么的,初学者看了就会头晕. ...
- 【开发工具】- Idea.2018.02注册码激活
1.从下面地址下载一个jar包,名称是 JetbrainsCrack-3.1-release-enc.jar 下载地址: 链接: https://pan.baidu.com/s/1VZjklI3qh ...
- 学习笔记之DBeaver
DBeaver Community | Free Universal Database Tool https://dbeaver.io/ Universal Database Tool Free mu ...
- JMeter学习笔记(十八)——返回的响应数据出现中文乱码_解决方案
一.问题描述 使用jmeter过程中遇到了请求返回的响应数据出现中文乱码 二.原因分析 当没有对响应数据or响应页面设置支持解析中文的编码时,JMeter则会以默认的ISO-8859-1格式解析,而其 ...
- MySQL MHA候选主库选择
MHA在选择新主库时,会将所有存活的从库分为下面几类: 存活从库数组:挑选所有存活的从库 最新从库数组: 挑选Master_Log_File+Read_Master_Log_Pos最高的从库 优选从库 ...
- 利用Git钩子实现代码发布
目录 1.什么是git钩子 2.安装一个钩子 3.常用的钩子脚本类型 3.1 客户端钩子 3.1.1 pre-commit 3.1.2 prepare-commit-msg 3.1.3 commit- ...
- 记一次对上传对jsp限制的绕过
当访问网站任何.jsp后缀的文件时都会显示如下图所示或者session timeout等提示, 并且网站防护会,对上传大马和一句话会被查杀. 解决方法: 利用jspx包含,利用jspx包含图片或者cs ...