sqoop2基本架構、部署和個人使用感受

一、概述

    隨着公司集羣升級到2.x,hadoop周邊的一些工具也進行了版本的更新。這次主要說說sqoop2的升級和部署,其中sqoop1和sqoop2基本框架和用法發生翻天覆地的改變,其對版本的向下兼容做的十分不好,接下來慢慢說,總之各種值得吐槽的地方。

二、sqoop2的基本框架,以及部署

(1)首先說說sqoop1和sqoop2區別

    這兩個版本是完全不兼容的,其具體的版本號區別爲1.4.x爲sqoop1,1.99x爲sqoop2。sqoop1和sqoop2在架構和用法上已經完全不同。

在架構上,sqoop2引入了sqoop server(具體服務器爲tomcat),對connector實現了集中的管理。其訪問方式也變得多樣化了,其可以通過REST API、JAVA API、WEB UI以及CLI控制檯方式進行訪問。另外,其在安全性能方面也有一定的改善,在sqoop1中我們經常用腳本的方式將HDFS中的數據導入到mysql中,或者反過來將mysql數據導入到HDFS中,其中在腳本里邊都要顯示指定mysql數據庫的用戶名和密碼的,安全性做的不是太完善。在sqoop2中,如果是通過CLI方式訪問的話,會有一個交互過程界面,你輸入的密碼信息不被看到。下圖是sqoop1和sqoop2簡單架構對比:

wKiom1OtGw-xcD4sAAFDETuQy_c685.jpg

wKioL1OtGuHAOCISAAGbmEFRBzQ551.jpg

(2)sqoop2部署步驟

1、下載sqoop-1.99.x版本的sqoop,並進行解壓。

2、配置好SQOOP_HOME等環境變量,並用source是~/.bash_profile文件即時生效。

3、配置sqoop server

   修改$SQOOP_HOME/server/conf/catalina.properties,修改common.loader屬性,加入hadoop2.x的各種lib包,具體指向路徑爲$HADOOP_HOME/share/hadoop/common/*.jar,

$HADOOP_HOME/share/hadoop/common/lib/*.jar,$HADOOP_HOME/share/hadoop/yarn/*.jar,$HADOOP_HOME/share/hadoop/hdfs/*.jar,$HADOOP_HOME,/share/hadoop/mapreduce/*.jar,沒有路徑用逗號分開。另外,在$SQOOP_HOME中建個文件夾例如hadoop_lib,然後將這些jar包cp到此文件夾中,最後將此文件夾路徑添加到common.loader屬性中,這種方法更加直觀些。

   修改$SQOOP_HOME/server/conf/sqoop.properties,修改org.apache.sqoop.submission.engine.mapreduce.configuration.directory屬性值爲$HADOOP_HOME/etc/hadoop。

    另外,要主要一下$SQOOP_HOME/server/conf/server.xml中的tomcat端口問題,確保這些端口不會和你其他tomcat服務器衝突。

   修改配置完畢就可以啓動sqoop server了,啓動命令:$SQOOP_HOME/bin/sqoop.sh server start,啓動完看服務器日誌如果沒有錯誤就ok了。

在修改sqoop server配置文件,啓動過程中你可能會遇到各種問題,這些問題可能是log4j或者是tomcat的相關錯誤問題,還是不難解決的。其中包衝突問題我就遇到了,看sqoop server日誌:

wKiom1OtLADifjbjAAXi55uWwz8398.jpg

剛剛看到這個錯誤信息可能不容易往jar包衝突這方面想,出現這個錯誤的原因是剛剛$SQOOP_HOME/server/conf/catalina.properties文件common.loader屬性中的hadoop2.x lib中的jar包和sqoop server的web項目中的lib中的包衝突了,解決方法可以將$SQOOP_HOME/server/webapps/sqoop/WEB-INF/lib中的log4j-1.2.16.jar刪掉就ok了。

三、sqoop2的Java API使用

    sqoop2中的java api使用方式和sqoop1是完全不同的。其基本流程爲:

1、添加sqoop2的Dependency包。

<dependency>
  <groupId>org.apache.sqoop</groupId>
    <artifactId>sqoop-client</artifactId>
    <version>1.99.3</version>
</dependency>

2、創建Connetion。

3、利用之前創建的ConnectionID去創建job。

4、提交job。

具體代碼整理了一下:

import org.apache.sqoop.client.SqoopClient;
import org.apache.sqoop.model.MConnection;
import org.apache.sqoop.model.MConnectionForms;
import org.apache.sqoop.model.MJob;
import org.apache.sqoop.model.MJobForms;
import org.apache.sqoop.model.MSubmission;
import org.apache.sqoop.submission.counter.Counter;
import org.apache.sqoop.submission.counter.CounterGroup;
import org.apache.sqoop.submission.counter.Counters;
import org.apache.sqoop.validation.Status;

public class Sqoop2Access {
	public static void main(String[] args) {
		//1、--------------Initialization(創建sqoop client)-------------------
		String url = "http://localhost:12000/sqoop/";
		SqoopClient client = new SqoopClient(url);
		client.setServerUrl(url);
		
		//2、--------------Create Connection--------------
		//Dummy connection object
		MConnection newCon = client.newConnection(1);//1爲指定的ConnectionID

		//Get connection and framework forms. Set name for connection
		MConnectionForms conForms = newCon.getConnectorPart();
		MConnectionForms frameworkForms = newCon.getFrameworkPart();
		newCon.setName("MyConnection");

		//Set connection forms values
		conForms.getStringInput("connection.connectionString").setValue("jdbc:mysql://localhost/mysqlTestDB");
		conForms.getStringInput("connection.jdbcDriver").setValue("com.mysql.jdbc.Driver");
		conForms.getStringInput("connection.username").setValue("root");
		conForms.getStringInput("connection.password").setValue("root");

		frameworkForms.getIntegerInput("security.maxConnections").setValue(0);

		
		Status status  = client.createConnection(newCon);
		//檢測鏈接的相關狀態
		if(status.canProceed()) {
		 System.out.println("Created. New Connection ID : " +newCon.getPersistenceId());
		} else {
		 System.out.println("Check for status and forms error ");
		}
		
		//3、--------------create job(import job)--------------
		//Creating dummy job object(利用connectionID去創建job)
		MJob newjob = client.newJob(newCon.getPersistenceId(), org.apache.sqoop.model.MJob.Type.IMPORT);
		MJobForms connectorForm = newjob.getConnectorPart();
		MJobForms frameworkForm = newjob.getFrameworkPart();

		newjob.setName("ImportJob");
		//Database configuration
		connectorForm.getStringInput("table.schemaName").setValue("");
		//Input either table name or sql
		connectorForm.getStringInput("table.tableName").setValue("table");
		//connectorForm.getStringInput("table.sql").setValue("select id,name from table where ${CONDITIONS}");
		connectorForm.getStringInput("table.columns").setValue("id,name");
		connectorForm.getStringInput("table.partitionColumn").setValue("id");
		//Set boundary value only if required
		//connectorForm.getStringInput("table.boundaryQuery").setValue("");

		//Output configurations
		frameworkForm.getEnumInput("output.storageType").setValue("HDFS");
		frameworkForm.getEnumInput("output.outputFormat").setValue("TEXT_FILE");//Other option: SEQUENCE_FILE
		frameworkForm.getStringInput("output.outputDirectory").setValue("/output");

		//Job resources
		frameworkForm.getIntegerInput("throttling.extractors").setValue(1);
		frameworkForm.getIntegerInput("throttling.loaders").setValue(1);

		Status statusJob = client.createJob(newjob);
		//檢測作業狀態相關信息
		if(statusJob.canProceed()) {
		 System.out.println("New Job ID: "+ newjob.getPersistenceId());
		} else {
		 System.out.println("Check for status and forms error ");
		}

		//4、--------------Job Submission--------------
		//Job submission start
		MSubmission submission = client.startSubmission(newjob.getPersistenceId());
		System.out.println("Status : " + submission.getStatus());
		if(submission.getStatus().isRunning() && submission.getProgress() != -1) {
		  System.out.println("Progress : " + String.format("%.2f %%", submission.getProgress() * 100));
		}
		System.out.println("Hadoop job id :" + submission.getExternalId());
		System.out.println("Job link : " + submission.getExternalLink());
		Counters counters = submission.getCounters();
		if(counters != null) {
		  System.out.println("Counters:");
		  for(CounterGroup group : counters) {
		    System.out.print("\t");
		    System.out.println(group.getName());
		    for(Counter counter : group) {
		      System.out.print("\t\t");
		      System.out.print(counter.getName());
		      System.out.print(": ");
		      System.out.println(counter.getValue());
		    }
		  }
		}
		if(submission.getExceptionInfo() != null) {
		  System.out.println("Exception info : " +submission.getExceptionInfo());
		}


		//Check job status
		MSubmission submission1 = client.getSubmissionStatus(newjob.getPersistenceId());
		if(submission1.getStatus().isRunning() && submission1.getProgress() != -1) {
		  System.out.println("Progress : " + String.format("%.2f %%", submission1.getProgress() * 100));
		}

		//Stop a running job
		//submission1.stopSubmission(jid);
		

	}
}

另外,如果你使用CLI直接訪問的話請參考:http://sqoop.apache.org/docs/1.99.3/CommandLineClient.html ; REST API方式訪問請參考:http://sqoop.apache.org/docs/1.99.3/RESTAPI.html 。

四、sqoop2的安裝和使用總結

    在sqoop2的升級部署以及使用的過程中有諸多吐槽的地方。第一,sqoop2的部署相比於sqoop1複雜的多,雖然官方網站中的install guide中的文檔還是比較詳細的,但是其中沒有考慮到hadoop和sqoop webSite包衝突問題,以及沒有對在部署過程中有可能出現的問題進行相關提示。第二,sqoop2和sqoop1的兼容性問題沒有做到很好的處理,這個是我個人最不能忍受的地方。其中,體現的最明顯的地方就是,之前我在公司寫項目的時候是用sqoop1的import或者export腳本去實現HDFS和RDBMS之間的數據轉移的,現在我將sqoop1升級到sqoop2之後,import和export腳本再也無法使用了,這樣的話我不得不重新將在項目中用sqoop1中的import和export腳本實現的功能用JAVA API去重新編寫,這樣使得升級超級不平滑,我認爲這個是sqoop2做的最不好的地方。


參考文獻:http://sqoop.apache.org/docs/1.99.3/index.html 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章