Sqoop源码浅析

来源:互联网 发布:新郎接亲游戏知乎 编辑:程序博客网 时间:2024/06/16 00:51

前言

Apache Sqoop应该是在hadoop与SQL间上最常用的数据导入导出工具了。最近应为面试,简单看了一下sqoop 1.4.6的源码,整理如下。

驱动类——Sqoop

org.apache.sqoop.Sqoop是sqoop工具的启动类。
主要作用:

  1. 解析命令行传入的参数
  2. 根据参数调用相应的SqoopTool

工具类——SqoopTool

org.apache.sqoop.Sqoop.SqoopTool是一个抽象类,是所有SqoopTool的父类。它的类属性TOOLS里保存了所有SqoopTool的类对象。
主要作用:
1. 解析命令行传入的参数
2. 输出帮助信息
3. 完成具体功能

子类主要通过实现抽象方法public abstract int run(SqoopOptions options);来实现功能。
下面详细介绍一下数据库导入工具类。

数据库导入工具类——ImportTool

org.apache.sqoop.tool.ImportTool是sqoop实现数据库导入功能的工具类。

ImportTool最核心的两个属性

protected ConnManager manager;private CodeGenTool codeGenerator;

manager负责所有查询数据库的操作。
codeGenerator负责将表结构映射为java类。

ImportTool的run方法

  @Override  /** {@inheritDoc} */  public int run(SqoopOptions options) {    HiveImport hiveImport = null;    if (allTables) {      // We got into this method, but we should be in a subclass.      // (This method only handles a single table)      // This should not be reached, but for sanity's sake, test here.      LOG.error("ImportTool.run() can only handle a single table.");      return 1;    }    if (!init(options)) {      return 1;    }    codeGenerator.setManager(manager);    try {      if (options.doHiveImport()) {        hiveImport = new HiveImport(options, manager, options.getConf(), false);      }      // Import a single table (or query) the user specified.      importTable(options, options.getTableName(), hiveImport);    } catch (IllegalArgumentException iea) {        LOG.error("Imported Failed: " + iea.getMessage());        if (System.getProperty(Sqoop.SQOOP_RETHROW_PROPERTY) != null) {          throw iea;        }        return 1;    } catch (IOException ioe) {      LOG.error("Encountered IOException running import job: "          + StringUtils.stringifyException(ioe));      if (System.getProperty(Sqoop.SQOOP_RETHROW_PROPERTY) != null) {        throw new RuntimeException(ioe);      } else {        return 1;      }    } catch (ImportException ie) {      LOG.error("Error during import: " + ie.toString());      if (System.getProperty(Sqoop.SQOOP_RETHROW_PROPERTY) != null) {        throw new RuntimeException(ie);      } else {        return 1;      }    } finally {      destroy(options);    }    return 0;  }  /** 1. Import a table or query. 2. @return true if an import was performed, false otherwise.   */  protected boolean importTable(SqoopOptions options, String tableName,      HiveImport hiveImport) throws IOException, ImportException {    String jarFile = null;    // Generate the ORM code for the tables.    jarFile = codeGenerator.generateORM(options, tableName);    Path outputPath = getOutputPath(options, tableName);    // Do the actual import.    ImportJobContext context = new ImportJobContext(tableName, jarFile,        options, outputPath);    // If we're doing an incremental import, set up the    // filtering conditions used to get the latest records.    if (!initIncrementalConstraints(options, context)) {      return false;    }    if (options.isDeleteMode()) {      deleteTargetDir(context);    }    if (null != tableName) {      manager.importTable(context);    } else {      manager.importQuery(context);    }    if (options.isAppendMode()) {      AppendUtils app = new AppendUtils(context);      app.append();    } else if (options.getIncrementalMode() == SqoopOptions.IncrementalMode.DateLastModified) {      lastModifiedMerge(options, context);    }    // If the user wants this table to be in Hive, perform that post-load.    if (options.doHiveImport()) {      // For Parquet file, the import action will create hive table directly via      // kite. So there is no need to do hive import as a post step again.      if (options.getFileLayout() != SqoopOptions.FileLayout.ParquetFile) {        hiveImport.importTable(tableName, options.getHiveTableName(), false);      }    }    saveIncrementalState(options);    return true;  }

在run方法中执行init(options)时,会根据命令行参数,利用org.apache.sqoop.ConnFactory生成对应的ConnManager对象。
在importTable方法中,codeGenerator会将表结构对应的java类写入jar文件。这个jar文件和其他选项会构造出一个ImportJobContext对象。
如果是增量模式,initIncrementalConstraints(options, context)会把IncrementalTestColumn的最大值保存在options.incrementalLastValue属性中,作为下一次增量的起点。
manager利用ImportJobContext对象中的信息完成表数据的导入。
manager完成importTable或importQuery后,程序再根据命令行参数选择将新数据追加到老数据、将新老数据合并或者将新数据导入hive。如果是增量任务,整个ImportTool对象会被保存到metastore。

连接类——ConnManager

org.apache.sqoop.manager.ConnManager是SqoopTool导入导出数据的核心类。它有3个子类:

  1. DummyManager——主要用于单元测试
  2. MainFrameManager——连接主机,目前只支持通过FTP协议
  3. SqlManager——连接各种支持JDBC连接的数据库

SqlManager

SqlManager查询数据库主要有两种方式:本地模式和分布式模式
本地模式即直接在当前JVM中查询,比如查询表的结构。
分布式模式下进行数据导入导出的查询,如表的导入导出。importTable()方法是一个典型的例子。

/**   * Default implementation of importTable() is to launch a MapReduce job   * via DataDrivenImportJob to read the table with DataDrivenDBInputFormat.   */  public void importTable(com.cloudera.sqoop.manager.ImportJobContext context)      throws IOException, ImportException {    String tableName = context.getTableName();    String jarFile = context.getJarFile();    SqoopOptions opts = context.getOptions();    context.setConnManager(this);    ImportJobBase importer;    if (opts.getHBaseTable() != null) {      // Import to HBase.      if (!HBaseUtil.isHBaseJarPresent()) {        throw new ImportException("HBase jars are not present in "            + "classpath, cannot import to HBase!");      }      if (!opts.isBulkLoadEnabled()){        importer = new HBaseImportJob(opts, context);      } else {        importer = new HBaseBulkImportJob(opts, context);      }    } else if (opts.getAccumuloTable() != null) {       // Import to Accumulo.       if (!AccumuloUtil.isAccumuloJarPresent()) {         throw new ImportException("Accumulo jars are not present in "             + "classpath, cannot import to Accumulo!");       }       importer = new AccumuloImportJob(opts, context);    } else {      // Import to HDFS.      importer = new DataDrivenImportJob(opts, context.getInputFormat(),              context);    }    checkTableImportOptions(context);    String splitCol = getSplitColumn(opts, tableName);    importer.runImport(tableName, jarFile, splitCol, opts.getConf());  }

根据命令行参数的选项,数据将被导入HBase、Accumulo或者HDFS。
在DataDrivenImportJob的runImport方法中,可以看到MapReduce Job的构造和提交过程。
Job的InputFormat的默认类型是DataDrivenDBInputFormat。OutputFormat默认为null,使用hadoop默认的FileOutputFormat。MapperClass根据输出文件格式的不同而不同。可能的文件格式有纯文本、avro、parquet等。
HBaseImportJob、AccumuloImportJob是DataDrivenImportJob的子类。为了将数据导入HBase 和Accumulo,它们实现了不同的MapperClass和OutputFormat。

其他工具类

其他工具类的实现方式和ImportTool差不多,大部分应该比ImportTool简单。这里就不一一罗列了。

0 0
原创粉丝点击