关于hive的ClosedByInterruptException异常新动向3

通过这两天的不断研究源码,发现与这个相关的hadoop源码是DFSClient、DistributedFileSystem、JobInProgress、JobClient、JobTracker等

与hive相关的源码是CliDriver、Driver、ExecDriver、TaskRunner、Task、MoveTask等。

之前设置了暂停100毫秒的方式后,后来也测试出将严重影响MR运行的效率,从198秒增加到498秒,这非常慢了。


最终通过hive提交job的位置发现,以ExecDriver代码为例,代码如下:

// Finally SUBMIT the JOB!

rj = jc.submitJob(job);


在第435行,hadoop版本我是1.0.3。

jc是一个JobClient的实例,submitJob方法如下:

public RunningJob submitJob(JobConf job) throws FileNotFoundException,

                                                  IOException {

    try {

      return submitJobInternal(job);

    } catch (InterruptedException ie) {

      throw new IOException("interrupted", ie);

    } catch (ClassNotFoundException cnfe) {

      throw new IOException("class not found", cnfe);

    }

  }


该方法调用了submitJobInternal方法,该方法代码较多,截取主要代码段如下:

//

          // Now, actually submit the job (using the submit name)

          //

          printTokens(jobId, jobCopy.getCredentials());

          status = jobSubmitClient.submitJob(

              jobId, submitJobDir.toString(), jobCopy.getCredentials());

          JobProfile prof = jobSubmitClient.getJobProfile(jobId);

          if (status != null && prof != null) {

            return new NetworkedJob(status, prof, jobSubmitClient);

          } else {

            throw new IOException("Could not launch job");

          }


其中jobSubmitClient是一个接口类型的变量,JobTracker和LocalJobRunner是它的实现。

这里以JobTracker类为例,该方法实现也较多,截取主要代码如下;

JobInfo jobInfo = null;

    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();

    synchronized (this) {

      if (jobs.containsKey(jobId)) {

        // job already running, don't start twice

        return jobs.get(jobId).getStatus();

      }

      jobInfo = new JobInfo(jobId, new Text(ugi.getShortUserName()),

          new Path(jobSubmitDir));

    }

    

    // Create the JobInProgress, do not lock the JobTracker since

    // we are about to copy job.xml from HDFS

    JobInProgress job = null;

    try {

      job = new JobInProgress(this, this.conf, jobInfo, 0, ts);

    } catch (Exception e) {

      throw new IOException(e);

    }


这里要主要了重点来了。创建JobInProgress这个对象时,最后有个finally方法段里有一个方法,如下:

FileSystem.closeAllForUGI(UserGroupInformation.getCurrentUser());

都会对文件系统进行关闭操作,包括DFSClient进行关闭、 DistributedFileSystem关闭还有相关的IO流也关闭。

因为此方法是一个静态方法,里面的CACHE这个对象也是全局对象(只有一个)。代码如下:

public staticvoid closeAllForUGI(UserGroupInformation ugi) 

  throws IOException {

    CACHE.closeAll(ugi);

  }


这是当hive支持parallel模式时,就会同时创建多个JobInProgress对象,然后都会对CACHE进行关闭操作,这样就会导致正在执行的远程调用方法,被中断掉。也就出现了ClosedByInterruptException这个异常了。另外之前还有一个问题,报错信息是“Filesystem closed”这个消息,也是因为DFSClient不在运行状态导致,代码如下:

private void checkOpen()throws IOException {

    if (!clientRunning) {

      IOException result = new IOException("Filesystem closed");

      throw result;

    }

  }



通过综上分析,感觉导致此异常的最终原因查明了,不过我还是要证实下我这个猜测是否正确。

采取的措施有二:

第一:我采用的方式是暂时将finally方法段里closeAllForUGI的调用注释掉,检验其是否还有ClosedByInterruptException异常出现。目前正在测试中,两天后给出测试结果。

其二:分析和评估下注释掉closeAllForUGI方法的调用后,有那些影响和隐患。



目前通过几天的测试、调试和研究后,发现还是没解决这个并发问题,暂没想到更好的解决方式了,所以将绕开这个问题,hive的parallel模式不采用,并修改调度程序使之并行化(有一定技巧在里面,需要在实战中提高这方面的意识)。

那么此问题通过了一个月的努力,就暂告一段落了。望以后随着对hadoop使用的不断加深和接触的业务越来越多广泛,能找出解决方式。

另外补充下,如果计算量较大,一个统计的数据量超过了2亿(这里指记录),那么hadoop在初次搭建的集群建议在10台以上,这样有几个好处:

第一:给优化腾出充足的时间

第二:方便业务的扩展

第三:体验hadoop(为什么这么说呢,个人通过使用和测试后,认为当集群的节点太少的话,运行太慢,能测试出很好的优化结果有难度。)

你可能感兴趣的:(exception,hadoop,cache,测试,null,parallel)