如何判断Parquet文件是否存在页级CRC校验及排查传输损坏相关问题
最近我在PySpark读取Parquet表时遇到了一个错误:
Caused by: org.apache.parquet.io.ParquetDecodingException: could not verify page integrity, CRC checksum verification failed
这个表是通过FTP传输的,后来我删掉目标端的表重新从源端传输后,错误就消失了——显然第一次传输时至少有一个Parquet文件在网络传输中损坏了。
这让我担心用来传输表的通用脚本不够健壮,没法应对传输中的数据损坏,所以我想检查其他用同样脚本传输的表。但我怀疑大部分表的Parquet文件根本没带页级校验和,不然团队早就遇到这类错误了。查了资料后我知道,Parquet的页头校验和是可选的,默认不开启,有校验和的话会是整数,没有的话就是NA。
先说说Python工具的局限性
我一开始想找Python的解决方案,但试下来发现不太可行:pyarrow没法获取页级数据(试过相关方法但行不通),而parquet-tools、parquet-cli这些Python包的粒度不够细,满足不了查看页级CRC的需求。
可行的方案:用Java版Parquet-Tools
后来我发现Java版本的parquet-tools能实现这个需求,最省心的方式是用Docker镜像来运行,不用自己折腾Java环境。具体命令如下:
$ docker container run -v ./local/path/to/parquet:/container/path/to/parquet --rm -t rm3l/parquet-tools:latest dump -n /container/path/to/parquet/test.parquet
实际测试验证
我做了两个测试来验证怎么通过工具判断CRC是否存在,以及检测损坏情况:
测试A:开启页级CRC写入
用Spark写出Parquet时开启校验和:data = [("John", 28), ("Anna", 23), ("Mike", 35), ("Sara", 30), ("David", 40)] columns = ["Name", "Age"] df = spark.createDataFrame(data, columns) df.repartition(1).write.option("parquet.page.write-checksum.enabled", "true").parquet(...)用parquet-tools查看时,输出里会出现这样的行:
page 0: DLE:RLE RLE:BIT_PACKED VLE:PLAIN ST:[no stats for this column] CRC:[PAGE CORRUPT] SZ:47 VC:5
这里有点意外,明明文件没被损坏,但输出显示CRC:[PAGE CORRUPT],这个情况还需要进一步排查,但至少能确认开启了CRC校验。测试B:关闭页级CRC写入
写出时关闭校验和:data = [("John", 28), ("Anna", 23), ("Mike", 35), ("Sara", 30), ("David", 40)] columns = ["Name", "Age"] df = spark.createDataFrame(data, columns) df.repartition(1).write.option("parquet.page.write-checksum.enabled", "false").parquet(...)用parquet-tools查看时,输出对应的行是:
page 0: DLE:RLE RLE:BIT_PACKED VLE:PLAIN ST:[no stats for this column] CRC:[none] SZ:47 VC:5
总结
通过Java版parquet-tools的输出,我们可以快速判断Parquet文件是否开启了页级CRC校验:如果输出中显示CRC:[none],说明没有开启;如果显示具体数值或CRC:[PAGE CORRUPT],说明开启了校验和(后者大概率意味着文件损坏)。对于用通用脚本传输的表,我们可以批量用这个工具检查,排查可能存在的传输损坏问题。
备注:内容来源于stack exchange,提问作者Matthew Thomas

