Python SparkStreaming应用程序太慢

Python SparkStreaming应用程序太慢,python,apache-spark,pyspark,spark-streaming,dstream,Python,Apache Spark,Pyspark,Spark Streaming,Dstream,在开发SparkStreaming应用程序(python)时,我不能完全确定是否理解它的工作原理。 我只需要读取一个json文件流(在目录中弹出)并对每个json对象和引用执行连接操作,然后将其写回文本文件。这是我的密码: config = configparser.ConfigParser() config.read("config.conf") def getSparkSessionInstance(sparkConf): if ("sparkSessionSingletonInstanc

在开发SparkStreaming应用程序(python)时,我不能完全确定是否理解它的工作原理。 我只需要读取一个json文件流(在目录中弹出)并对每个json对象和引用执行连接操作,然后将其写回文本文件。这是我的密码:

config = configparser.ConfigParser()
config.read("config.conf")

def getSparkSessionInstance(sparkConf):
if ("sparkSessionSingletonInstance" not in globals()):
    globals()["sparkSessionSingletonInstance"] = SparkSession \
        .builder \
        .config(conf=sparkConf) \
        .getOrCreate()
return globals()["sparkSessionSingletonInstance"]

# Création du contexte
sc = SparkContext()
ssc = StreamingContext(sc, int(config["Variables"]["batch_period_spark"]))
sqlCtxt = getSparkSessionInstance(sc.getConf())
df_ref = sqlCtxt.read.json("file://" + config["Paths"]["path_ref"])
df_ref.createOrReplaceTempView("REF")
df_ref.cache()
output = config["Paths"]["path_DATAs_enri"]


# Fonction de traitement des DATAs
def process(rdd):
        if rdd.count() > 0:
                #print(rdd.toDebugString)
                df_DATAs = sqlCtxt.read.json(rdd)
                df_DATAs.createOrReplaceTempView("DATAs")
                df_enri=sqlCtxt.sql("SELECT DATAs.*, REF.Name, REF.Mail FROM DATAs, REF WHERE DATAs.ID = REF.ID")
                df_enri.createOrReplaceTempView("DATAs_enri")
                df_enri.write.mode('append').json("file://" + output)
                if(df_enri.count() < df_DATAs.count()):
                        df_fail = sqlCtxt.sql("SELECT * FROM DATAs WHERE DATAs.ID NOT IN (SELECT ID FROM DATAs_enri)")
                        df_fail.show()


# Configuration du stream et lancement
files = ssc.textFileStream("file://" + config["Paths"]["path_stream_DATAs"])
files.foreachRDD(process)
print("[GO]")
ssc.start()
ssc.awaitTermination()

嗯,它正在工作,但我有一个问题:过程很慢,过程延迟在增加。我在当地[*]工作,恐怕没有平行性。。。在监控UI中,我一次只能看到一个执行者和一个作业。有没有更简单的方法?和数据流上的转换函数一样?是否缺少一个配置变量?

您的代码运行缓慢有几个原因

关于工人,正如我看到的,我没有看到任何地方你设定了工人的数量。因此,它将从默认的工人数量开始,这意味着可能是1。在另一方面,您正在读取一个可能并没有那个么大的文件,而spark并没有进行并行处理

另一方面,您需要理解代码中的几个步骤:

  • 您有很多计数:
    如果rdd.count()大于0:;如果(df_enri.count()
    ,则计数非常昂贵,这是流式数据中的一个减少阶段,并且您的计数是计数的3倍
  • 连接也很昂贵,在流式处理中进行连接不是很好,您做的是正确的
    df_ref.cache()
    ,但是,连接会进行洗牌,而且成本很高

  • 我的建议是,不要做那个失败的步骤,从代码中删除它。它不起作用,只是不保存数据。另一件事,设置更多的工人或更多的核心执行:
    spark.executor.cores=2
    ,如您所见。

    好的,非常感谢这些建议!我还有一个问题,我的if中的第一个计数是为了防止Spark在rdd出现之前处理它们。SparkStreaming在流上启动操作,即使还没有什么要处理的,这是正常的吗?因为如果我不这样做,它会告诉我我正在处理空RDD…第一个
    count()
    我建议您使用函数
    isEmpty()
    这可以更快地检查您的RDD是否为空。这不会生成洗牌。
    spark.master                    local[*]
    spark.executor.memory           3g
    spark.driver.memory             3g
    spark.python.worker.memory      3g
    spark.memory.fraction           0.9
    spark.driver.maxResultSize      3g
    spark.memory.storageFraction    0.9
    spark.eventLog.enabled          true