• HFile文件解析异常解决


    1. 场景说明

    需要对离线的 HFile 进行解析,默认可以使用如下的方式:

    hbase org.apache.hadoop.hbase.io.hfile.HFile -f $HDFS_PATH -p -s
    

    这样存在几个问题:

    1. 需要依赖 hbase 的环境
    2. -p 选项输出的结果,打印出来的不是 value 的值,里面默认使用的是 Bytes.toBinaryString
    3. 太重了,无关的内容不需要

    所以需要对上面的实现方式改造一下。

    阅读了源代码之后,了解到 HFile 里面包含的 main 方法初始化了一个 HFilePrettyPrinter 对象,把外部的参数传递给 HFilePrettyPrinter 的对象执行具体的工作。类图如下:

    HFile 解析类

    从道理上,只需要把 HFilePrettyPrinter 的代码精简一下,就可以直接拿来用。

    开始的时候,为了测试的方便,直接使用 hbase -jar $CLASSNAME args 来做验证,都是 ok 的。
    输出的日志如下(后续会通过日志输出比对调试):

    INFO  hfile.CacheConfig: Allocating LruBlockCache with maximum size 1.4g
    INFO  blobstore.BlobFileCache: BlobFileCache Initialize
    INFO  util.ChecksumType: Checksum using org.apache.hadoop.util.PureJavaCrc32
    INFO  util.ChecksumType: Checksum can use org.apache.hadoop.util.PureJavaCrc32C
    WARN  hdfs.DFSClient: Short circuit access failed
    INFO  util.NativeCodeLoader: Trying to load the custom-built native-hadoop library...
    INFO  util.NativeCodeLoader: Loaded the native-hadoop library
    WARN  snappy.LoadSnappy: Snappy native library is available
    INFO  snappy.LoadSnappy: Snappy native library loaded
    INFO  compress.CodecPool: Got brand-new decompressor
    

    但是一旦脱离了 hbase (/usr/lib/hbase/bin/hbase)这个宿主,直接运行 main 方法,总是报错。

    2.异常分析

    2.1 CRC32校验类找不到

    最开始出现的是如下的错误:

    INFO  org.apache.hadoop.hbase.io.hfile.CacheConfig - Allocating LruBlockCache with maximum size 1.4g
    INFO  org.apache.hadoop.hbase.blobstore.BlobFileCache - BlobFileCache Initialize
    INFO  org.apache.hadoop.hbase.util.ChecksumType - org.apache.hadoop.util.PureJavaCrc32 not available.
    INFO  org.apache.hadoop.hbase.util.ChecksumType - Checksum can use java.util.zip.CRC32
    INFO  org.apache.hadoop.hbase.util.ChecksumType - org.apache.hadoop.util.PureJavaCrc32C not available.
    INFO  org.apache.hadoop.hdfs.DFSClient - Failed to read block blk_-2063727887249910869_1998268 on local machineorg.apache.hadoop.ipc.RPC$VersionMismatch: Protocol org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol version mismatch. (client = 4, server = 5)
            at org.apache.hadoop.ipc.RPC.getProxy(RPC.java:401)
            at org.apache.hadoop.ipc.RPC.getProxy(RPC.java:370) 
            at org.apache.hadoop.hdfs.DFSClient.createClientDatanodeProtocolProxy(DFSClient.java:174) 
            at org.apache.hadoop.hdfs.BlockReaderLocal$LocalDatanodeInfo.getDatanodeProxy(BlockReaderLocal.java:89) 
            at org.apache.hadoop.hdfs.BlockReaderLocal$LocalDatanodeInfo.access$200(BlockReaderLocal.java:64) 
            at org.apache.hadoop.hdfs.BlockReaderLocal.getBlockPathInfo(BlockReaderLocal.java:211) 
            at org.apache.hadoop.hdfs.BlockReaderLocal.newBlockReader(BlockReaderLocal.java:133) 
            at org.apache.hadoop.hdfs.DFSClient.getLocalBlockReader(DFSClient.java:358) 
    

    关键部分是org.apache.hadoop.util.PureJavaCrc32 not available,这个问题比较明显,是lib 包中缺少必要的类。
    为了避免类似的情况,直接用 hbase classpath 把打印出默认的依赖关系,然后把所有的依赖 jar 都加进来。

    2.2 文件block 找不到

    添加完 jar 包后,重新运行,还是报错,关键点是:
    Failed to read block blk_-2063727887249910869_1998268 on local machineorg.apache.hadoop.ipc.RPC$VersionMismatch: Protocol org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol version mismatch. (client = 4, server = 5)

    这里在分析的时候犯了一个错误:首先注意到的是 Failed to read block ... on local machine,而且在日志里面,后面会不断地从本地节点的 datanode 重试,直到超时;且在后面的日志中有 org.apache.hadoop.hdfs.DFSClient.getLocalBlockReader 的信息,莫名其妙地怎么会使用了 LocalBlockReader 呢?

    开始就顺着这个思路去搜,找到了HDFS-2757,症状有点像,一看是个老版本的 bug,心说这下操蛋了。
    但是显然我只是在读,没有写文件啊?再考虑下,既然使用 hbase 调起的方式可以正常使用,就证明现在的版本是可行的,可能这不是主要问题。

    再看后面,Protocol org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol version mismatch. (client = 4, server = 5),之前没有写过 RPC 的程序,在 Google 上搜索了一下,从这里这里了解到,这种是典型的 RPC 协议版本不一致的问题。

    特别是上面的作者在回复提问的时候,先是确认了 hadoop 的版本,故我转去确认了 lib 库中 hadoop 相关 jar 的版本,结果发现如下:

    Hadoop Jar 版本差别 这个确实没招了。。。之前使用不仔细造成的。

    于是把 lib 包里面原有的全部清空,然后重新导入 hbase classpath 的输出jar。

    2.3 NativeCodeLoader问题

    上一步处理完之后,再次运行,还是报错:

    INFO  org.apache.hadoop.hbase.io.hfile.CacheConfig - Allocating LruBlockCache with maximum size 1.4g
    INFO  org.apache.hadoop.hbase.blobstore.BlobFileCache - BlobFileCache Initialize
    INFO  org.apache.hadoop.hbase.util.ChecksumType - Checksum using org.apache.hadoop.util.PureJavaCrc32
    INFO  org.apache.hadoop.hbase.util.ChecksumType - Checksum can use org.apache.hadoop.util.PureJavaCrc32C
    WARN  org.apache.hadoop.hdfs.DFSClient - Short circuit access failed
    INFO  org.apache.hadoop.util.NativeCodeLoader - Trying to load the custom-built native-hadoop library...
    ERROR org.apache.hadoop.util.NativeCodeLoader - Failed to load native-hadoop with error: java.lang.UnsatisfiedLinkError: no hadoop in java.library.path
    ERROR org.apache.hadoop.util.NativeCodeLoader - java.library.path=/usr/java/jdk1.6.0_31/jre/lib/amd64/server:/usr/java/jdk1.6.0_31/jre/lib/amd64:/usr/java/jdk1.6.0_31/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
    WARN  org.apache.hadoop.util.NativeCodeLoader - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
    ERROR org.apache.hadoop.io.compress.snappy.LoadSnappy - Failed to load snappy with error: java.lang.UnsatisfiedLinkError: no snappy in java.library.path
    WARN  org.apache.hadoop.io.compress.snappy.LoadSnappy - Snappy native library not loaded
    Exception in thread "main" java.lang.RuntimeException: native snappy library not available
            at org.apache.hadoop.io.compress.SnappyCodec.getDecompressorType(SnappyCodec.java:189)
            at org.apache.hadoop.io.compress.CodecPool.getDecompressor(CodecPool.java:138)
            at org.apache.hadoop.hbase.io.hfile.Compression$Algorithm.getDecompressor(Compression.java:290)
    

    关键信息是:

    1. no hadoop in java.library.path
    2. no snappy in java.library.path

    这里从新去 /usr/lib/hbase/bin/hbase 文件中查看了下,发现里面有对 $JAVA_PLATFORM$JAVA_LIBRARY_PATH 这两个环境变量的整理。

    这里 sudo 修改了 hbase 的执行文件,中间把上面两个环境变量打印出来。第一个 $JAVA_PLATFORM 显示的是 Linux-amd64-64,第二个是/usr/lib/hadoop/lib/native/Linux-amd64-64文件夹的内容。

    然后把 $JAVA_LIBRARY_PATH的内容,通过 -Djava.library.path= 的方式,添加到 Eclipse 的 VM Variables 中。

    再次运行,正常。

    3. 总结

    花了一个下午的时间来 DEBUG 这个异常,回过头看,有以下几点需要注意:

    1. 要认真读日志,通过打印出来的错误堆栈,分清楚哪些是真正错误的源头,哪些是错误扩散的结果。比如花了半天研究 HDFS-2757,后来发现没关系,这个就很没有必要;
    2. 认识到 hbase、hadoop 这种工具,除了看得到的组件代码之后,看不到额环境配置等内容,也很重要,没有合适的环境配置,正确的代码也是没法正常运行的,需要进一步花一点时间了解组件的运行时环境的配置需求;
    3. 排错是个厚积薄发的事情,遇到大小问题都要好好思考,多看源代码,解决起来才会有思路。

    参考

    1. HDFS-2757
    2. RPC 报错问答1
    3. RPC 报错问答2
  • 相关阅读:
    [转]WebForm中使用MVC
    [转]外贸出口流程图
    [转]查看SQL Server被锁的表以及如何解锁
    [转]RDL Report in Visual Studio New page per Record
    [转]Sql Server Report Service 的部署问题
    [转]ASP.NET MVC4中@model使用多个类型实例的方法
    [转]告别写计划的烦恼!一页纸四步打造出一份牛逼的商业计划
    [转]LINQ: Using INNER JOIN, Group and SUM
    [转] 比特币『私钥』『公钥』『钱包地址』间的关系
    [转]SQL SERVER数据库删除LOG文件和清空日志的方案
  • 原文地址:https://www.cnblogs.com/YFYkuner/p/5161702.html
Copyright © 2020-2023  润新知