scala版本的sparkstreaming基于Direct连接kafka0.8旧版本开发详解
文章目录
- scala版本的sparkstreaming基于Direct连接kafka0.8旧版本开发详解
- 1:本次/基于Direct的方式读取kafka数据
- 1.1Direct方式讲解
- 1.1.1**特点**
- 1.1.2:这种方式有如下优点:
- 1.2进行消息生产
- 2:代码开发
- 2.1:偏移量管理:checkpoint
- 2.2:完整demo
- 结果运行
- 2.3:checkpoint+kafka自己管理
1:本次/基于Direct的方式读取kafka数据
1.1Direct方式讲解
/**
* 摒弃了高阶的kafkaConsumerAPI直接从kafkaBrokers获取信息,可以保证每条消息只被消费一次
* 特点:
* - No receivers:没有receivers接收器,直接从kafka拉取数据
* - Offsets:不用zookeeper存储offsets,偏移量是通过stream自己跟踪记录的,可以通过HasOffsetRanges获取offset
* - Failure Recovery故障恢复:需要开启sparkContext的checkpoint功能
* - End-to-end semantics最终一致性:保证消息被消费且只消费一次
* @return DStream of (Kafka message key, Kafka message value)
1.1.1特点
Direct的方式是会直接操作kafka底层的元数据信息,这样如果计算失败了,可以把数据重新读一下,重新处理。即数据一定会被处理。拉数据,是RDD在执行的时候直接去拉数据。
由于直接操作的是kafka,kafka就相当于你底层的文件系统。这个时候能保证严格的事务一致性,即一定会被处理,而且只会被处理一次。而Receiver的方式则不能保证,因为Receiver和ZK中的数据可能不同步,Spark Streaming可能会重复消费数据。而Direct api直接是操作kafka的,spark streaming自己负责追踪消费这个数据的偏移量或者offset,并且自己保存到checkpoint,所以它的数据一定是同步的,一定不会被重复。
底层是直接读数据,没有所谓的Receiver,直接是周期性(Batch Intervel)的查询kafka,处理数据的时候,我们会使用基于kafka原生的Consumer api来获取kafka中特定范围(offset范围)中的数据,这个时候,Direct Api访问kafka带来的一个显而易见的性能上的好处就是,如果你要读取多个partition,Spark也会创建RDD的partition,这个时候RDD的partition和kafka的partition是一致的。所以增加kafka中的topic的partition数量可以提高并行度。
偏移量:默认从最新偏移量(largest)开始消费。如果设置了auto.offset.reset参数值为smallest将从最小偏移处开始消费。
**```
**API介绍****
/*
1:createDirectStream的api详细介绍:
参数列表3个:
1.1: ssc:sparkstreaming对象
1.2: kafkaParams:map类型的kafka配置列表
1.3:topics
类型限制
* @param topics Names of the topics to consume
* @tparam K: type of Kafka message key:kafka消息的keyd的类型
* @tparam V :type of Kafka message value
* @tparam KD :type of Kafka message key decoder
* @tparam VD :type of Kafka message value decoder
* @return DStream of (Kafka message key, Kafka message value)
* decoder:编解码器,将字节数组byte转换为字符流进行解码
### 1:开发准备
1:集群正常启动
2:创建kafka的topic
kafka-console-producer.sh \
--broker-list hdp01:9092,hdp02:9092,hdp03:9092 \
--topic spark01
1.1.2:这种方式有如下优点:
1、简化并行读取:如果要读取多个partition,不需要创建多个输入DStream然后对它们进行union操作。Spark会创建跟Kafka partition一样多的RDD partition,并且会并行从Kafka中读取数据。所以在Kafka partition和RDD partition之间,有一个一对一的映射关系。
2、高性能:如果要保证零数据丢失,在基于receiver的方式中,需要开启WAL机制。这种方式其实效率低下,因为数据实际上被复制了两份,Kafka自己本身就有高可靠的机制,会对数据复制一份,而这里又会复制一份到WAL中。而基于direct的方式,不依赖Receiver,不需要开启WAL机制,只要Kafka中作了数据的复制,那么就可以通过Kafka的副本进行恢复。
3、一次且仅一次的事务机制:
基于receiver的方式,是使用Kafka的高阶API来在ZooKeeper中保存消费过的offset的。这是消费Kafka数据的传统方式。这种方式配合着WAL机制可以保证数据零丢失的高可靠性,但是却无法保证数据被处理一次且仅一次,可能会处理两次。因为Spark和ZooKeeper之间可能是不同步的。
4、降低资源。
Direct不需要Receivers,其申请的Executors全部参与到计算任务中;而Receiver-based则需要专门的Receivers来读取Kafka数据且不参与计算。因此相同的资源申请,Direct 能够支持更大的业务。
5、降低内存。
Receiver-based的Receiver与其他Exectuor是异步的,并持续不断接收数据,对于小业务量的场景还好,如果遇到大业务量时,需要提高Receiver的内存,但是参与计算的Executor并无需那么多的内存。而Direct 因为没有Receiver,而是在计算时读取数据,然后直接计算,所以对内存的要求很低。实际应用中我们可以把原先的10G降至现在的2-4G左右。
6、鲁棒性更好。
Receiver-based方法需要Receivers来异步持续不断的读取数据,因此遇到网络、存储负载等因素,导致实时任务出现堆积,但Receivers却还在持续读取数据,此种情况很容易导致计算崩溃。Direct 则没有这种顾虑,其Driver在触发batch 计算任务时,才会读取数据并计算。队列出现堆积并不会引起程序的失败。
基于direct的方式,使用kafka的简单api,Spark Streaming自己就负责追踪消费的offset,并保存在checkpoint中。Spark自己一定是同步的,因此可以保证数据是消费一次且仅消费一次
1.2进行消息生产
2:代码开发
2.1:偏移量管理:checkpoint
偏移量管理有三种方式,本次采checkpoint
————————————————————————————
2.2:完整demo
代码逻辑必须写在createSSC方法中
object _04StreamingGetOrCreate {
//利用checkpoint本地磁盘进行offset偏移量管理,数据存放
//可本地可hdfs
val checkpointPath = "file:///C:\\Users\\Administrator.SC-201905261418\\Desktop\\bigdata开发实例\\checkpoint"
def main(args: Array[String]): Unit = {
val context = StreamingContext.getOrCreate(checkpointPath, createSSC)
context.start()
context.awaitTermination()
}
//代码逻辑必须写在createSSC中
def createSSC(): StreamingContext = {
val conf = new SparkConf().setAppName("local test checkpoint").setMaster("local[2]")
val ssc = new StreamingContext(conf, Seconds(10))
val kafkaParams = Map[String, String](
"bootstrap.servers" -> "hdp01:9092,hdp02:9092,hdp03:9092",
"group.id" -> "comsumer1",
//smallest从偏移量最早的位置开始读取,开发多用此配置
//本次demo即保存在checkpoint中
"auto.offset.reset" -> "smallest",
"enable.auto.commit" -> "false",
//此时我们相当于在消费数据,指定反序列数据的方式,实现org.apache.kafka.common.serialization.Deserializer的类
"key.deserializer" -> "org.apache.kafka.common.serialization.StringDeserializer",
"value.deserializer" -> "org.apache.kafka.common.serialization.StringDeserializer")
val topic = Set("spark01")
ssc.checkpoint(checkpointPath)
//dstreams是一个rdd的集合rdds
val dstreams = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, topic)
//配置持久定时写到checkpoint,参数建议:5-10倍的batch
dstreams.checkpoint(Seconds(100))
dstreams.print()
//获取到数据lines
val lines = dstreams.map(_._2)
lines.print()
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1L)).reduceByKey(_ + _)
wordCounts.print()
println("start rdd")
ssc
}
}
结果运行
2.3:checkpoint+kafka自己管理
在这里插入代码片