1.Reciver方式
基于Receiver方式,Spark内部使用 Kafka High Level API持续地从 Kafka 接收数据并存储在 Spark Executor的内存中,根据batch time触发job去消费接收到的数据,消费者不能自己去维护consumed offset,同时Kafka也不关心数据是否丢失。当向 Zookeeper 中更新完 offset 后,Driver 如果挂掉,那么 Driver 下的 Executors 就会被 kill 掉,会造成数据丢失。为了防止数据丢失,我们还需要在Spark Streaming中添加预写日志,这将同步地将所有接收到的Kafka数据保存到分布式文件系统(如HDFS)的预写日志中。
2.Direct方式
Spark 1.3中引入了这种新的无接收者的“Direct”方法,以确保更强的端到端保证。与使用接收者接收数据不同,该模式通过定期扫描所订阅的 Kafka 每个主题的每个分区的最新的 offset以确定当前批处理数据偏移范围。
相比 Receiver 方式,Direct 方式具有以下几个优势:
1.简单并行化:使用Direct, Spark stream将创建与Kafka分区一样多的RDD分区,这些分区将并行地从Kafka读取数据。
2.效率:在Receiver方法中,要实现零数据丢失,需要将数据存储在预写日志中。这实际上是低效的,数据会被有效地复制两次——一次由Kafka复制,第二次由Write Ahead日志复制。Direct方法消除了这个问题,因为没有接收器,因此不需要提前写日志。只要Kafka保留,消息可以从Kafka恢复。
3.Exactly-once语义:Receiver使用kafka high level Api在zookeeper中存储消耗的偏移量。Spark流可靠接收的数据和Zookeeper跟踪的偏移量之间可能产生不一致导致数据丢失。Direct不使用zookeeper,而是通过Spark Streaming的checkpoint进行追踪,不会有不一样的情况。
Scala代码:
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
/**
* @Author: ch
* @Date: 11/07/2020 8:46 PM
* @Version 1.0
* @Describe:
*/
object SparkStreamingKMeansKafkaExample {
def main(args: Array[String]) {
val spark = SparkSession.builder()
.appName("KafkaRecciver")
.master("local[*]")
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.getOrCreate()
val sc = spark.sparkContext
val checkpointDir = "F:\\path"
val ssc: StreamingContext = new StreamingContext(sc, Milliseconds(10))
ssc.checkpoint("hdfs://host:9000/checkpoint")
val kafkaParams: Map[String, Object] = Map[String, Object](
"bootstrap.servers" -> "localhost:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "use_a_separate_group_id_for_each_stream",
"auto.offset.reset" -> "earliest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
val topics = Array("occupancy")
val stream: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream[String, String](
ssc,
PreferConsistent,
Subscribe[String, String](topics, kafkaParams)
)
val resultDStream = stream.map(x=>x.value())//从kafka读取出来的数据包含了很多信息,包括了信息时间戳等,所以要获取value值
resultDStream.print()
ssc.start()
ssc.awaitTermination()
}
}
kafkaParams可以看其官网的Streams API:http://kafka.apache.org/0100/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。