美文网首页
记一次Hadoop1.0.4集群的事故

记一次Hadoop1.0.4集群的事故

作者: yannhuang | 来源:发表于2017-06-27 16:39 被阅读50次

    由于历史原因,公司内部还在使用hadoop1.0.4版本的集群,而且上面运行的任务还挺多。当初开发这套系统的员工几乎都离职了,所以这块成了鸡肋。撤掉吧,上面还有好的用户;迁移吧,涉及的东西太多,影响比较大。所以这套系统就只能一直这样维护着。

    终于在一次集群的大事故中,让大家认识到,再也不能用hadoop1.0集群了。

    一、问题的原因

    Hadoop1.0的HDFS元数据是存放在fsimage中的,编辑日志存放在edits;SecondaryNameNode节点负责把edits日志合并到fsimage中,用于数据恢复。当遇到edits日志中存在异常的时候,元数据不再往edits文件中写,而是写入edits.new文件中。当发现这个问题的时候,就需要在hdfs的安全模式下,使用以下命令进行恢复

    hadoop dfsadmin -saveNamespace

    但是在没恢复之前,如果重启namenode节点,问题就大了。我们这边由于某个mr采用多路径输出,把中文输出到文件路径中了,导致在元数据中存放了乱码,启动namenode的时候,fsimage一直检查不通过,异常如下:

    ERROR org.apache.hadoop.hdfs.server.namenode.NameNode: java.io.IOException: Found lease for non-existent file /data/houraggregate/eventself_day/2017/05/01/14/output/_temporary/_attempt_201602020826_208092_r_000006_0/part-r-00006-DESelf_Coi#@$%^Pd
        at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFilesUnderConstruction(FSImage.java:1440)
        at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:986)
        at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:830)
        at org.apache.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:377)
        at org.apache.hadoop.hdfs.server.namenode.FSDirectory.loadFSImage(FSDirectory.java:100)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.initialize(FSNamesystem.java:388)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.<init>(FSNamesystem.java:362)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:276)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:496)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1279)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1288)
    

    二、处理过程

    既然是edit文件出异常,就应该修复该文件。查看资料是可以通过以下命令把edit这个二进制文件解析成xml文件的

    hdfs oev -i edits -o edits.xml //解析edits文件
    hdfs oiv -i fsimage -o fsimage.xml //解析fsimage文件

    解析完成后通过以下命令重新转回二进制文件

    hdfs oev -i edits.xml -o edits -p binary //转换xml文件成edits文件
    hdfs oiv -i fsimage.xml-o fsimage -p binary //转换xml文件成fsimage文件

    由于系统是hadoop1.0.4所以不存在 hdfs 这个命令,只好把文件拷贝到hadoop2.6.0上进行操作。

    打开转换后的xml文件,把存在乱码的Recode标签内的记录都删除掉,然后在转换为二进制文件。

    当解析 image 文件的时候,发现解析不了,查看资料才发现,原来fsimage文件是与hadoop版本一一对应的。

    所以上面所做的所有工作都是无效的。

    后面想到,能不能通过查看hadoop写fsimage文件的过程,然后反过来解析呢?但是这样处理,会耗费大量的时间去阅读源码,实际情况是不允许的。转念一想,能不能把判断乱码的代码修改为,如果遇到就跳过呢?

    通过查看异常的堆栈,找到是 FSImage 类的以下代码报出的异常

    for (int i = 0; i < size; i++) {
          INodeFileUnderConstruction cons = readINodeUnderConstruction(in);
    
          // verify that file exists in namespace
          String path = cons.getLocalName();
          
          INode old = fsDir.getFileINode(path);
          if (old == null) {
            // 从此处报出异常
            throw new IOException("Found lease for non-existent file " + path);
          }
          if (old.isDirectory()) {
            throw new IOException("Found lease for directory " + path);
          }
          INodeFile oldnode = (INodeFile) old;
          fsDir.replaceNode(path, oldnode, cons);
          fs.leaseManager.addLease(cons.clientName, path); 
        }
    

    把代码修改如下:

    for (int i = 0; i < size; i++) {
          INodeFileUnderConstruction cons = readINodeUnderConstruction(in);
    
          // verify that file exists in namespace
          String path = cons.getLocalName();
          
          // 添加判断,把存在异常的路径过滤掉
          if (path.contains("_temporary")){
              continue;
          }
          
          INode old = fsDir.getFileINode(path);
          if (old == null) {
            throw new IOException("Found lease for non-existent file " + path);
          }
          if (old.isDirectory()) {
            throw new IOException("Found lease for directory " + path);
          }
          INodeFile oldnode = (INodeFile) old;
          fsDir.replaceNode(path, oldnode, cons);
          fs.leaseManager.addLease(cons.clientName, path); 
        }
    

    然后编译FSImage类,打包到hadoop-core-1.0.4.jar中,放入hadoop1.0.4 namenode节点的对应目录下,重启namenode进程,终于能正常启动了。

    三、总结

    1、不能在edits.new存在的情况下,重启namenode进程

    2、hdfs中的路径不能存在乱码,最后就用字母数字下划线这些比较通用的字符来做路径

    相关文章

      网友评论

          本文标题:记一次Hadoop1.0.4集群的事故

          本文链接:https://www.haomeiwen.com/subject/uueecxtx.html