【发布时间】:2022-05-14 12:07:05
【问题描述】:
我正在从一个消息应用程序收集数据,我目前正在使用 Flume,它每天发送大约 5000 万条记录
我想用卡夫卡, 使用 Spark Streaming 从 Kafka 消费 并将其持久化到 hadoop 并使用 impala 进行查询
我尝试过的每种方法都有问题..
方法 1 - 将 RDD 保存为 parquet,将外部 hive parquet 表指向 parquet 目录
// scala
val ssc = new StreamingContext(sparkConf, Seconds(bucketsize.toInt))
val lines = KafkaUtils.createStream(ssc, zkQuorum, group, topicMap).map(_._2)
lines.foreachRDD(rdd => {
// 1 - Create a SchemaRDD object from the rdd and specify the schema
val SchemaRDD1 = sqlContext.jsonRDD(rdd, schema)
// 2 - register it as a spark sql table
SchemaRDD1.registerTempTable("sparktable")
// 3 - qry sparktable to produce another SchemaRDD object of the data needed 'finalParquet'. and persist this as parquet files
val finalParquet = sqlContext.sql(sql)
finalParquet.saveAsParquetFile(dir)
问题是 finalParquet.saveAsParquetFile 输出大量文件,从 Kafka 接收的 Dstream 输出 1 分钟批量大小的 200 多个文件。 它输出许多文件的原因是因为计算是分布的,如另一篇文章中所述-how to make saveAsTextFile NOT split output into multiple file?
但是,所提出的解决方案对我来说似乎不是最佳的,例如正如一位用户所说 - 如果您的数据很少,只有一个输出文件才是一个好主意。
方法 2 - 使用 HiveContext。将 RDD 数据直接插入到 hive 表中
# python
sqlContext = HiveContext(sc)
ssc = StreamingContext(sc, int(batch_interval))
kvs = KafkaUtils.createStream(ssc, zkQuorum, group, {topics: 1})
lines = kvs.map(lambda x: x[1]).persist(StorageLevel.MEMORY_AND_DISK_SER)
lines.foreachRDD(sendRecord)
def sendRecord(rdd):
sql = "INSERT INTO TABLE table select * from beacon_sparktable"
# 1 - Apply the schema to the RDD creating a data frame 'beaconDF'
beaconDF = sqlContext.jsonRDD(rdd,schema)
# 2- Register the DataFrame as a spark sql table.
beaconDF.registerTempTable("beacon_sparktable")
# 3 - insert to hive directly from a qry on the spark sql table
sqlContext.sql(sql);
这很好用,它直接插入到镶木地板表中,但由于处理时间超过了批处理间隔时间,因此批处理存在调度延迟。 消费者跟不上正在生产的东西,要处理的批次开始排队。
似乎写入 hive 很慢。我尝试调整批处理间隔大小,运行更多消费者实例。
总结
鉴于存在多个文件的问题以及写入 hive 的潜在延迟,从 Spark Streaming 中持久保存大数据的最佳方法是什么? 其他人在做什么?
此处已提出类似问题,但他对与太多文件相对的目录存在问题 How to make Spark Streaming write its output so that Impala can read it?
非常感谢您的帮助
【问题讨论】:
-
您可以为输出流设置不同的窗口。
val lines = KafkaUtils.createStream(ssc, zkQuorum, group, topicMap).map(_._2).window(Minutes(15)).foreachRDD(rdd => -
这对我来说似乎是一个非常常见的用例,我很惊讶没有人回答它。我想我会建议使用数据库,因为 Spark 本身并不能真正取代它。尝试 Cassandra 或 HBase(HBase 的学习曲线非常陡峭)。
标签: hadoop apache-kafka spark-streaming