我正在收集来自消息应用程序的数据,我目前正在使用Flume,它每天发送大约5000万条记录
我想用Kafka, 使用Spark Streaming从Kafka消费 并将其持久化为hadoop并使用impala进行查询
我遇到的每种方法都遇到了问题..
方法1 - 将rdd保存为镶木地板,将外部蜂巢木地板指向镶木地板目录
// 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输出超过200个文件,批量大小为1分钟。 它输出许多文件的原因是因为计算是按照另一个后how to make saveAsTextFile NOT split output into multiple file?中所解释的那样进行分配的。 对于我来说,所提出的解决方案对我来说似乎不是最佳的。正如一个用户所说 - 如果您的数据非常少,那么只有一个输出文件是个好主意。
方法2 - 使用Hivecontext。将rdd数据直接插入配置表
# 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);
这样可以正常工作,它可以直接插入到镶木地板表中,但由于处理时间超过了批处理间隔时间,因此批次会有计划延迟。 消费者无法跟上生产的产品,处理的批次开始排队。
似乎写入蜂巢的速度很慢。香港专业教育学院尝试调整批量intervla大小,运行更多的消费者实例。总结
从Spark Streaming中保留大数据的最佳方法是什么?考虑到多个文件存在问题以及写入hive会有潜在的延迟? 其他人在做什么?
这里已经提出了类似的问题,但是他的目录存在问题太多了 How to make Spark Streaming write its output so that Impala can read it?
非常感谢您的帮助
答案 0 :(得分:0)
在解决方案#2中,可以通过每个RDD的分区数来控制创建的文件数。
见这个例子:
// create a Hive table (assume it's already existing)
sqlContext.sql("CREATE TABLE test (id int, txt string) STORED AS PARQUET")
// create a RDD with 2 records and only 1 partition
val rdd = sc.parallelize(List( List(1, "hello"), List(2, "world") ), 1)
// create a DataFrame from the RDD
val schema = StructType(Seq(
StructField("id", IntegerType, nullable = false),
StructField("txt", StringType, nullable = false)
))
val df = sqlContext.createDataFrame(rdd.map( Row(_:_*) ), schema)
// this creates a single file, because the RDD has 1 partition
df.write.mode("append").saveAsTable("test")
现在,我想您可以使用从Kafka提取数据的频率,以及每个RDD的分区数(默认情况下,Kafka主题的分区,您可以通过重新分区来减少)。
我正在使用CDH 5.5.1中的Spark 1.5,我使用df.write.mode("append").saveAsTable("test")
或您的SQL字符串得到相同的结果。
答案 1 :(得分:0)
我认为小文件问题可以得到解决。您可能会基于kafka分区获取大量文件。对我来说,我有12个分区的Kafka主题,我使用spark.write.mode("append").parquet("/location/on/hdfs")
编写。
现在,根据您的要求,您可以添加coalesce(1)
或更多来减少文件数量。另一种选择是增加微型批次的持续时间。例如,如果您可以接受5分钟的写作延迟,那么您可以进行300秒的微批处理。
对于第二个问题,批次仅因为没有启用反压力而排队。首先,您应该验证一次可以处理的最大数量。一旦达到该数字,就可以设置spark.streaming.kafka.maxRatePerPartition
值和spark.streaming.backpressure.enabled=true
以启用每个微批的有限数量的记录。如果您仍然不能满足需求,那么唯一的选择就是增加主题的分区或增加spark应用程序的资源。