PySpark+Phoenix+HBase读取数据时遇Unread Block Data异常求助
java.lang.IllegalStateException: unread block data异常 问题详情
我是Python 2.6.x、PySpark、Spark 1.6、HBase 1.1的新手,尝试通过Apache Phoenix的Spark插件读取HBase表数据。
读取数据代码
dfRows = sparkConfig.getSqlContext().read\ .format('org.apache.phoenix.spark')\ .option('table', 'TableA')\ .option('zkUrl', 'xxx:2181:/hbase-secure')\ .load()
运行命令
spark-submit --master yarn-client --executor-memory 24G --driver-memory 20G --num-executors 10 --queue aQueue --jars /usr/hdp/2.6.1.40-4/phoenix/lib/phoenix-core-4.7.0.2.6.1.40-4.jar,/usr/hdp/current/phoenix-client/lib/hbase-client.jar,/usr/hdp/current/phoenix-client/phoenix-client.jar,/usr/hdp/2.6.1.40-4/hive2/lib/twill-zookeeper-0.6.0-incubating.jar,/usr/hdp/2.6.1.40-4/hive2/lib/twill-discovery-api-0.6.0-incubating.jar,/usr/hdp/2.6.1.40-4/hive2/lib/hive-hbase-handler.jar Test.py
异常情况
程序启动正常,但执行dfRows.first()时抛出如下异常:
Caused by: java.lang.IllegalStateException: unread block data
at java.io.ObjectInputStream$BlockDataInputStream.setBlockDataMode(ObjectInputStream.java:2449)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1385)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2018)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1942)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1808)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at org.apache.spark.serializer.JavaDeserializationStream.readObject(JavaSerializer.scala:76)
at org.apache.spark.serializer.JavaSerializerInstance.deserialize(JavaSerializer.scala:115)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:207)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
... 1 more
解决方案
这个unread block data异常几乎都是序列化/反序列化不兼容或者JAR包版本冲突导致的,结合你的Spark 1.6 + HDP 2.6环境,给你几个具体的排查和修复步骤:
1. 精简并清理冲突的JAR包
你当前的--jars参数里包含了多个重复或不必要的依赖:
phoenix-core.jar和phoenix-client.jar存在重复,HDP环境下phoenix-client.jar已经包含了phoenix-core的全部内容,只保留前者即可hbase-client.jar和hive-hbase-handler.jar不需要手动添加,YARN集群会自动从HDP的共享库加载对应版本的依赖,手动添加反而容易引发版本不匹配
建议把--jars简化为:
--jars /usr/hdp/current/phoenix-client/phoenix-client.jar,/usr/hdp/2.6.1.40-4/hive2/lib/twill-zookeeper-0.6.0-incubating.jar,/usr/hdp/2.6.1.40-4/hive2/lib/twill-discovery-api-0.6.0-incubating.jar
2. 确保Java版本全集群一致
Spark 1.6对Java版本的一致性要求很高,如果Driver端和Executor端Java版本不同(比如一个用Java7,一个用Java8),很容易出现序列化异常。你可以这样检查:
- 本地Driver的Java版本:执行
java -version - YARN集群Executor的Java版本:查看YARN配置中的
yarn.nodemanager.java.home参数,确保和Driver端一致
3. 切换到Kryo序列化器
Spark默认的Java序列化器对复杂的HBase/Phoenix对象支持不够稳定,建议切换到Kryo序列化器,同时注册Phoenix的Kryo注册器:
在你的Spark配置代码中添加:
sparkConfig.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") sparkConfig.set("spark.kryo.registrator", "org.apache.phoenix.spark.PhoenixKryoRegistrator")
4. 验证Phoenix与Spark的版本兼容性
你使用的Phoenix 4.7.0是HDP 2.6的默认版本,和Spark 1.6是兼容的,但如果上述步骤都试过还是不行,可以确认下phoenix-client.jar是否包含了Phoenix Spark插件的代码(HDP的官方包应该已经包含),如果没有的话,需要单独下载对应版本的Phoenix Spark插件JAR包添加到--jars中。
内容的提问来源于stack exchange,提问作者RookieDev

