Databricks PySpark写入Parquet生成空文件问题及临时目录配置咨询
多任务写入Azure Blob Storage出现0字节Parquet文件的解决方案
问题根源
你碰到的偶尔生成0字节Parquet文件的情况,确实是多任务共享默认临时目录引发的冲突。当Spark向Azure Blob Storage写入数据时,默认会在容器根目录创建_$azuretmpfolder$临时目录存储中间文件,多个任务同时写入同一容器时,会出现临时文件的读写竞争或覆盖,导致最终输出文件损坏,重新运行时无竞争则恢复正常。
可行解决方案
1. 为每个任务配置独立临时目录
Spark支持通过tempPath选项指定自定义临时目录,让每个任务使用专属路径,彻底避免冲突。可以结合任务ID、时间戳或UUID生成唯一临时路径:
import uuid from datetime import datetime # 生成唯一临时目录,确保每个任务路径不重复 unique_temp_dir = f"{output_blob_folder}/_task_temp_{uuid.uuid4().hex}_{datetime.now().strftime('%Y%m%d%H%M%S')}" ( spark_df.coalesce(1) .write.mode("overwrite") .option("header", "true") .option("tempPath", unique_temp_dir) # 指定独立临时目录 .format("parquet") .save(output_blob_folder) )
写入完成后,Spark会自动清理该临时目录,无需手动操作。
2. 移除coalesce(1)优化写入逻辑
代码中coalesce(1)强制合并为单个文件,会将所有数据集中到一个Executor节点,既降低写入性能,又加剧了单文件写入时的冲突概率。如果业务不要求必须生成单个文件,建议删除该配置,让Spark自动分区写入,既能提升效率,也能减少竞争风险。
3. 增加输出校验与自动重试
可以在写入完成后校验文件大小,发现0字节文件时自动重试:
def check_parquet_files(output_path): # 遍历输出目录下的Parquet文件 for file in dbutils.fs.ls(output_path): if file.name.endswith(".parquet") and file.size == 0: return False return True # 初始写入 ( spark_df.coalesce(1) .write.mode("overwrite") .option("header", "true") .option("tempPath", unique_temp_dir) .format("parquet") .save(output_blob_folder) ) # 校验并重试,最多3次 retry_times = 0 max_retry = 3 while retry_times < max_retry: if check_parquet_files(output_blob_folder): break retry_times += 1 # 重试时使用新的临时目录 retry_temp_dir = f"{output_blob_folder}/_retry_temp_{retry_times}" ( spark_df.coalesce(1) .write.mode("overwrite") .option("header", "true") .option("tempPath", retry_temp_dir) .format("parquet") .save(output_blob_folder) )
社区验证
不少Databricks用户遇到过相同问题,通过配置独立临时目录或调整写入策略成功解决。虽然Azure官方文档未明确说明_$azuretmpfolder$的冲突场景,但社区实践已验证自定义临时目录是有效的解决手段。
内容的提问来源于stack exchange,提问作者Veronika Vrana
相关产品推荐
相关产品推荐

