我们有一个带有mapWithState
的spark 2.1流应用程序,启用spark.streaming.dynamicAllocation.enabled=true
。管道如下:
var rdd_out = ssc.textFileStream()
.map(convertToEvent(_))
.combineByKey(...., new HashPartitioner(partitions))
.mapWithState(stateSpec)
.map(s => sessionAnalysis(s))
.foreachRDD( rdd => rdd.toDF().....save(output));
流应用程序以2个执行程序启动,一段时间后它会创建新的执行程序,因为负载会按预期增加。问题是那些执行者不共享负载。
分区的数量足以扩散到新的执行器,并且密钥是均匀分布的,我设置了40多个分区,但我只能看到8个分区(2个执行器x每个4个核心) mapWithState
存储空间。我期待在分配新的执行程序时,将这8个分区拆分并分配给新的分区,但这种情况永远不会发生。
请告知。
谢谢,
答案 0 :(得分:0)
显然答案是盯着我的脸:)。根据下面的文档,RDD应该继承上游分区。
* Otherwise, we use a default HashPartitioner. For the number of partitions, if
* spark.default.parallelism is set, then we'll use the value from SparkContext
* defaultParallelism, otherwise we'll use the max number of upstream partitions.
mapWithState中的状态没有上游RDD。因此,除非您直接在状态中指定分区,否则将设置为默认并行度,如下面的示例所示。
val stateSpec = StateSpec.function(crediting.formSession _)
.timeout(timeout)
.numPartitions(partitions) // <----------
var rdd_out = ssc.textFileStream()
.map(convertToEvent(_))
.combineByKey(...., new HashPartitioner(partitions))
.mapWithState(stateSpec)
.map(s => sessionAnalysis(s))
.foreachRDD( rdd => rdd.toDF().....save(output));
仍然需要弄清楚如何使动态分配动态分区,这应该在运行时更改。