前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住给大家分享一下。点击跳转到网站:https://www.captainai.net/dongkelun
前言
记录一个Presto查询Hudi的异常的解决办法,本人目前对Presto还不是很熟,只是在使用过程中遇到了问题,记录一下异常解决方法以及过程
异常
1 | 2021-12-22T17:29:55.440+0800 ERROR SplitRunner-101-126 com.facebook.presto.execution.executor.TaskExecutor Error processing Split 20211222_092954_00047_8xk77.1.0.0-0 {path=hdfs://cluster1/warehouse/tablespace/managed/hive/test_dkl.db/test_hudi_1/069eddc2-f3bf-4efc-911b-3cb3aa523a8e-0_0-0-0_20211222172800.parquet, start=0, length=435116, fileSize=435116, fileModifiedTime=1640165281695, hosts=[], database=test_dkl, table=test_hudi_1, nodeSelectionStrategy=NO_PREFERENCE, partitionName=<UNPARTITIONED>, s3SelectPushdownEnabled=false, cacheQuotaRequirement=CacheQuotaRequirement{cacheQuotaScope=GLOBAL, quota=Optional.empty}} (start = 9.271133085962032E9, wall = 49 ms, cpu = 0 ms, wait = 0 ms, calls = 1) |
异常原因
原因是因为hdfs block块没有一个和presto在一个节点上的,要复现这个问题,可以把hdfs副本数改为1,这样可以比较快的复现,关于如何修改hdfs副本数:
修改hdfs-site.xml:1
2
3
4<property>
<name>dfs.replication</name>
<value>1</value>
</property>
注意:只修改集群的配置,只是修改了集群的默认值,还要注意客户端里的hdfs-site.xml也要修改,如果有的话
关于如何查看hdfs block块分布在哪几个节点:
1 | hdfs fsck hdfs://cluster1/warehouse/tablespace/managed/hive/test_dkl.db/test_hudi_1/069eddc2-f3bf-4efc-911b-3cb3aa523a8e-0_0-0-0_20211222172800.parquet -files -blocks -locations |
可以看到该文件只有一个副本在163,而presto实际在162
异常解决办法
修改presto catalog下面的配置文件hdfs-site.xml,添加
1 | <property> |
重启presto服务,即可解决问题
异常解决定位过程
网上没有搜到该异常的解决办法,只有一个异常与此类似,不过是hive/spark sql之间的异常:https://dongkelun.com/2018/05/20/hiveQueryException/。
怀疑是jar包版本问题,通过看源码解决,部分源码(可根据异常信息定位源码位置)
RemoteBlockReader.read
1 |
|
发现该方法直接抛异常,并且RemoteBlockReader
已经弃用了,在同一个包下面有一个RemoteBlockReader2
,并且它的read方法可以使用:
1 |
|
那么能不能通过分析源码,让它走RemoteBlockReader2
的逻辑呢,我们看一下异常的上一个调用
DFSInputStream$ByteBufferStrategy.doRead
1 |
|
查看blockReader的初始化:
1 | blockReader = new BlockReaderFactory(dfsClient.getConf()). |
再看BlockReaderFactory.build
1 | public BlockReader build() throws IOException { |
我们发现不管是getRemoteBlockReaderFromDomain
还是getRemoteBlockReaderFromTcp
,都是调用getRemoteBlockReader
:
1 | if (conf.useLegacyBlockReader) { |
可以看到,当conf.useLegacyBlockReader
为false时,就会走到RemoteBlockReader2
,那么再看一下conf.useLegacyBlockReader
1 | useLegacyBlockReader = conf.getBoolean( |
DFS_CLIENT_USE_LEGACY_BLOCKREADER_DEFAULT
为false,那么DFS_CLIENT_USE_LEGACY_BLOCKREADER
默认的应该为true,我们不用深究DFS_CLIENT_USE_LEGACY_BLOCKREADER
为啥为true,我们看看能不能通过修改配置将他的值设置为false
1 | public static final String DFS_CLIENT_USE_LEGACY_BLOCKREADER = "dfs.client.use.legacy.blockreader"; |
我们通过在hdfs-site.xml添加配置dfs.client.use.legacy.blockreader = false
,重启presto,发现解决了问题,大功告成!