sqoop2 源代码解析

##sqoop.config.dir从何而来?

看代码的时候,读到sqoopconfiguration类初始化的时候,总是觉得很疑惑这个system properties怎么凭空就冒出来了。

今天终于明白了,这个property是可以在shell里被指定的 。具体可以看sqoop.sh

JAVA_OPTS="$JAVA_OPTS -Dsqoop.config.dir=$SQOOP_CONF_DIR"

##job是如何被执行的

在JobManager.java里, 执行

public MSubmission start(String jobName, HttpEventContext ctx) 

来启动任务

而这个函数里面,真正有用的是

submissionEngine.submit(jobRequest);

那么submissionEngine是哪里来的呢?

String submissionEngineClassName =
      context.getString(DriverConstants.SYSCFG_SUBMISSION_ENGINE);//org.apache.sqoop.submission.mapreduce.MapreduceSubmissionEngine

submissionEngine = (SubmissionEngine) ClassUtils.instantiate(submissionEngineClassName);

所以需要阅读一下MapreduceSubmissionEngine.java的代码。

/*MapreduceSubmissionEngine.java*/
private void submitToCluster(MRJobRequest request, Job job) throws IOException, InterruptedException, ClassNotFoundException {
    job.submit();
    request.getJobSubmission().setExternalJobId(job.getJobID().toString());
    request.getJobSubmission().setExternalLink(job.getTrackingURL());
  }

在MapreduceSubmissionEngine.java里,最关键的还是submitToCluster方法。这里直接把一个job给提交了。这个job是个hadoop mapreduce类型的job,超出了sqoop的范围。需要去看看hadoop文档,对这一块是如何描述的。

看完之后发现,submit就是submit,并没有多余的花招。关键还是在于job是如何初始化的。所以还要往前翻,看看MapreduceSubmissionEngine.java里的public boolean submit(JobRequest mrJobRequest)方法。而在这个方法里,对于job的确做了一些配置,其实最关键的还是mapper class.

      job.setMapperClass(request.getMapperClass());
      job.setMapOutputKeyClass(request.getMapOutputKeyClass());
      job.setMapOutputValueClass(request.getMapOutputValueClass());

这个job提交之后,干些什么,其实都在mapperclass里定义了。所以接下来看看mapper class即可。

但是mapper class从何而来,其实来自于jobRequest.而这个变量,其实来自于jobmanager.java.

    JobRequest jobRequest = createJobRequest(mSubmission, job);
    // Bootstrap job to execute in the configured execution engine
    prepareJob(jobRequest);

这里的这个jobRequest,是通过createJobRequest这个函数构造的。如果我们进去看看,会发现,这个变量其实是由executionEngine构造的,虽然它在submission.start方法里。

  JobRequest jobRequest = executionEngine.createJobRequest();

不过这里还是按照jobRequest类的内容去配置,尚未涉及mapper class。接下来要看,prepareJob方法。

  void prepareJob(JobRequest request) {
    JobConfiguration jobConfiguration = (JobConfiguration) request.getDriverConfig();
    request.setExtractors(jobConfiguration.throttlingConfig.numExtractors);
    request.setLoaders(jobConfiguration.throttlingConfig.numLoaders);

    // Delegate rest of the job to execution engine
    executionEngine.prepareJob(request);
  }

然后我们又很神奇地发现,还是executionEngine在继续准备jobrequest.

而且,的确是在这里,我们找到了具体的配置命令:

    mrJobRequest.setMapperClass(SqoopMapper.class);
    mrJobRequest.setMapOutputKeyClass(SqoopWritable.class);
    mrJobRequest.setMapOutputValueClass(NullWritable.class);

所以说,在提交任务到hadoop engine前 ,用executionEngine设置好对应的mapper class.而真正的mapper class就是sqoopmapper.java.

这个文件是对mapper的扩展,里面最关键的就是run方法,这里重写了run方法。由于这是一个数据抽取任务,所以我们可以直接看和抽取相关的命令,也就是下文:

    String extractorName = conf.get(MRJobConstants.JOB_ETL_EXTRACTOR);
    Extractor extractor = (Extractor) ClassUtils.instantiate(extractorName);

这里定义了一个抽取器。这个抽取器叫什么名字?我们还要回executionEngine.preparejob里去看,因为是在那里设置的。

context.setString(MRJobConstants.JOB_ETL_EXTRACTOR, from.getExtractor().getName());

这里返回的是extractor class的名字。每个connector都有完整的一套。对于oracle connector来说,就是OracleJdbcExtractor.class。

每一个extrator class都要实现extract方法,而OracleJdbcExtractor在实现时,执行到以下命令,出错。

String mapperJdbcUrl = context.getString(mapperJdbcUrlPropertyName, null);
    try {
      connection = OracleConnectionFactory.createOracleJdbcConnection(
          OracleJdbcConnectorConstants.ORACLE_JDBC_DRIVER_CLASS,
          mapperJdbcUrl,
          linkConfiguration.connectionConfig.username,
          linkConfiguration.connectionConfig.password);
    } catch (SQLException ex) {
      throw new RuntimeException(String.format(
          "Unable to connect to the Oracle database at %s\nError:%s",
          linkConfiguration.connectionConfig.connectionString, ex
              .getMessage()), ex);
    }

所以,关键任务是找到以上参数的真实值。这些参数里,最容易有问题的其实是mapperjdbcurl,其他都很简单。

在这里,有一个getString的过程,要提取某个配置信息的值。这个配置信息的key="oraoop.mapper.jdbc.url.%d"。这个肯定是事先写进去的。

通过搜索程序里包含以上字样的代码,我发现问题主要出在OracleJdbcCommonInitializer.这个文件用于对连接进行初始化,而且还会给每一个mapper准备好jdbcurl。所以要看日志,看看在执行OracleJdbcCommonInitializer时,是否正确的连接了oracle数据库。然后再看看,它是如何重新翻译connectionstring的。

很关键,这里是真正去数据库里读取配置参数。是否读对了,需要检查对应的sql。:

    private static final String STMT_SELECT_CONFIG_FOR_CONFIGURATION =
      "SELECT "
        + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_ID) + ", "
        + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_CONFIGURABLE) + ", "
        + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_NAME) + ", "
        + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_TYPE) + ", "
        + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_INDEX)
        + " FROM " + CommonRepoUtils.getTableName(SCHEMA_SQOOP, TABLE_SQ_CONFIG_NAME)
        + " WHERE " + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_CONFIGURABLE) + " = ? "
        + " AND " + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_NAME) + " = ? "
        + " ORDER BY " + CommonRepoUtils.escapeColumnName(COLUMN_SQ_CFG_INDEX);

-- select "sq_cfg_id","sq_cfg_configurable","sq_cfg_name","sq_cfg_type","sq_cfg_index" from "sqoop"."SQ_CONFIG" where sq_cfg_configurable=? and sq_cfg_name=? order by sq_cfg_index

接下来就是要研究下面这段代码:

// the only driver config for the job
    Object driverConfig = ClassUtils
        .instantiate(Driver.getInstance().getDriverJobConfigurationClass());
    ConfigUtils.fromConfigs(job.getDriverConfig().getConfigs(), driverConfig);

##Context 从何而来?

在执行job的时候,有一个很重要的变量贯穿始终,它的名字叫context,里面存放了和执行有关的配置信息。接下来,就要研究一下,这个context从何而来。

第一次出现是在JobManager.java里。

  public synchronized void initialize() {
    MapContext context = SqoopConfiguration.getInstance().getContext();

Sqoop2居然支持,动态修改sqoop.properties参数文件,大概6000毫秒会reload一次。

仔细看了一下,context=sqoop.properties.

MapReduceSubmissionEngine.java里,将hadoop相关的配置文件读入内存,并放入jobClient的配置信息中。

jobClient = new JobClient(new JobConf(globalConfiguration));

看了半天,发现问题的关键还是在jobmanager.java里createJobRequest函数里。

在createJobRequest函数里,以下命令涉及配置信息

fromConnector.getLinkConfigurationClass()

而这个函数直接返回一个LinkConfiguration类。这个类里面存放了一个连接信息类,包括连接串,用户名,口令等信息,而且还能验证是否可以连接到数据库。

转载于:https://my.oschina.net/pearma/blog/830424

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值