DistributedRaidFileSystem引起的HDFS RAED不准问题,hdfs命令


一、问题描述

    在测试环境和线上运行相同的hql,而且表对应的数据量都是95G左右,但是发现在测试环境和线上的counter:HDFS RAED不一致,而且差一个数量级,线上只有8G左右,而测试环境达到95G,基本上就是全文件扫描,没有体现出RCFile的优势。

hql:

select gender,count(gender) from mds_user_info where dt="20150106" group by gender;

二、问题原因

   最后发现是因为测试环境配置了fs.hdfs.impl为DistributedRaidFileSystem导致的这个问题。

   hive在读取RCFile的时候,会用到RCFile的内部类Reader,由于咱们配置了fs.hdfs.impl,所以Reader在打开输入流时会走DistributedRaidFileSystem的open方法: 


DRFS中open方法返回的是ExtFSDataInputStream,而ExtFSDataInputStream中真正使用的时ExtFsInputStream。由于RCFile是按列储存的,所以在查询时会过滤掉很多不需要扫描的列,如下seekToNestKeyBuffer,会调用输入流中的skip方法。 


以下是在ExtFsInputStream的skip方法: 


注意红框部分,每次skip的时候,都会进行read操作,导致全文件读取。所以测试环境的counter计数和线上就不一致了。

如果咱们不配置fs.hdfs.impl,读取FCFile文件时就会走DistributedFileSystem,DistributedFileSystem的open方法打开的输入流是DFSInputStream,以下是DFSInputStream的skip方法:


没有read方法,而且最后会执行seek方法,设置下一次读取文件的位置。

三、解决办法

  从上面的第二点分析得出问题出在ExtFsInputStream的skip方法,那就从skip方法入手:

1、按照DFSInputStream的skip方法修改:

 

去掉read方法,最后调用seek方法设置下一次文件读取偏移量。

以下是这种修改的测试情况:

(1)、hql测试

测试了前面提到的hql:

select gender,count(gender) from mds_user_info where dt="20150106" group by gender; 

结果:测试环境的HDFS READ 和线上一致。

(2)、文本文件raid之后执行wordcount使用DistributedRaidFileSystem恢复测试

结果:丢块在执行wordcount时能通过DistributedRaidFileSystem正常恢复,并输出结果,由于是普通文本,直接进行全文件扫描,不会调用ExtFsInputStream中的skip方法。

(3)、RCFile文件raid之后执行hql使用DistributedRaidFileSystem恢复测试

hql:select count(*) from test_mds_user_info;

结果:出现异常,根据日志显示,出现了MissingBlock异常,而且进行了恢复操作,但是下次读的时候没有从恢复流里面读,而是还是从错误流里面读取数据了。

原因:先执行了skip方法调用了seek,设置偏移量,导致读取的时候如果出现异常并进行恢复时,恢复起始位置不对,导致恢复的输入流不可用。

2、综合DFSInputStream的skip方法和ExtFsInputStream的skip方法进行修改: 



在read方法: 


思路:DFSInputStream类新增skipNeedRead字段,默认为true。

1、如果先执行read方法,并且一起正常,设置skipNeedRead为false,后面在执行skip方法的时候执行seek,如果执行read方法出现异常,并通过raid进行恢复了,设置skipNeedRead为true,后面在执行skip方法的时候执行read。

2、如果先执行skip方法,由于skipNeedRead默认为true,所以skip方法会执行read操作,read数据时如果出现异常并进行恢复,设置skipNeedRead=true,以后执行skip时都会执行read操作,如果skip执行read方法未出现异常,则以后执行skip时执行seek操作,设置下一次文读取偏移量。

测试结果都OK。


相关内容