PySpark写入分区Parquet至HDFS报Buffer容量超限错误
问题根因
报错核心是Snappy压缩库版本与JDK环境不兼容。Parquet格式默认使用Snappy作为压缩编码,CSV写入默认不启用压缩因此可以正常执行;你测试的snappy-java 1.1.8.4、1.1.4均为旧版本,存在JDK8高补丁版本、JDK11+下的NIO ByteBuffer API调用兼容性bug:JDK9开始调整了ByteBuffer的limit()等方法的返回类型,旧版本snappy-java在字节码层面调用时会触发内存越界判断错误,抛出newLimit > capacity异常。saveAsTable默认也采用Parquet+Snappy格式写入,因此会触发完全相同的错误。
可行解决方案
按落地优先级从高到低排列:
- 升级snappy-java版本到1.1.10.1及以上
该版本官方修复了上述JDK兼容性问题。操作时需要替换集群所有节点Spark、Hadoop依赖目录下的snappy-java包,彻底清理旧版本snappy残留包避免类加载冲突。本地提交任务时,可以在提交命令中指定优先加载新版本依赖包:
替换完成后重启Spark服务即可正常执行写入。--conf spark.driver.extraClassPath=./snappy-java-1.1.10.5.jar --conf spark.executor.extraClassPath=./snappy-java-1.1.10.5.jar - 临时更换Parquet压缩编码规避Snappy依赖问题
如果暂时无法升级依赖,可以在写入Parquet时指定其他无兼容性问题的压缩格式(如gzip、zstd),无需修改Snappy相关依赖:
需要全局生效的话,可以在spark-defaults.conf中添加配置salesDfSpark.write.option("header",True) \ .partitionBy("Country") \ .option("compression", "gzip") \ .mode("overwrite") \ .parquet("hdfs://master:9000/sales/{}_{}.parquet".format(csvName,epochNow))spark.sql.parquet.compression.codec gzip,后续所有Parquet写入、saveAsTable操作都会默认使用gzip压缩。 - 回退JDK版本匹配旧Snappy依赖
如果必须使用旧版本snappy-java,需要将集群JDK回退到OpenJDK 8u181及更早的JDK8版本,禁止使用JDK11及以上版本。该方案存在安全漏洞风险,不推荐生产环境使用。
验证建议
修改配置或依赖后,先使用小体量测试DataFrame验证写入流程是否正常,确认无报错后再运行全量任务,避免资源浪费。
内容的提问来源于stack exchange,提问作者aurelius
相关产品推荐
相关产品推荐

