最近公司有個需求要讓我使用sqoop往hdfs導入一億的數據,要求5分鐘完成,但是網上關於sqoop的資料比較少,因此就對此做一些補充。
要使用sqoop做一些嵌入式的編程,需要做如下準備。
- window本地需要有hadoop的環境,這裏就不對hadoop的環境做闡述,可自行上網查找
- 下載sqoop的包,並配置sqoop的環境變量.
配置好環境之後,我們就可以開始編程了。
maven沒有sqoop的相關依賴
此時需要手動的將jar包添加到本地的maven倉庫中,上圖中,我們能看到sqoop-1.4.7.jar這個包,只要把這個包的添加到maven倉庫中,我們的開發環境就準備好了。
install:install-file -Dfile=<Jar包的地址>
-DgroupId=<Jar包的GroupId>
-DartifactId=<Jar包的引用名稱>
-Dversion=<Jar包的版本>
-Dpackaging=<Jar的打包方式>
//例子
mvn install:install-file
-Dfile=-Dfile=E:\U\spring-framework-4.2.4.RELEASE\libs\spring-context-4.2.4.RELEASE.jar
-DgroupId=org.springframework
-DartifactId=test
-Dversion=4.2.4
-Dpackaging=jar
大家根據自己的路徑去編譯即可。
現在說說如何實現10分鐘,導入一億的數據量
核心思想 分批導入
- 將一億的數據拆分,我這裏是以一千萬爲單位,將一億數據拆分成十份,利用線程池將任務發送,根但需要根據本地的硬件的性能做一些調整。
- 挖掘sqoop的參數的作用,努力提升服務的性能。
下面我將貼出部分代碼,以供大家參考:
將任務拆分
public boolean importFile(int threadCount, ImportModel sqlModel) throws Exception {
int flag=0;
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
StringBuffer stringBuffer = new StringBuffer();
//線程池爲線程安全
CustomThreadPoolExecutor pool = threadUtil.poolExecutor(threadCount);
HashMap<String,Double> map=progressManager.getMap();
for (int i = 1; i <= threadCount; i++) {
int index = i;
String[] args = ImportUtil.importFile(sqlModel, threadCount, i * splitPoint,i == 1 ? 0 : (i - 1) * splitPoint);
pool.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
int result = sqoopUtil.submitSqoop(args, "import");
if (result == 1) {
stringBuffer.append("[" + (index == 1 ? 0 : (index - 1) * splitPoint) + "," + index * splitPoint + "]");
}else{
double current=index* 1.0 / threadCount;
lock.lock();
//進度存到Map中,“yanger”後面需要連上數據庫 獲取用戶id
Double pre=map.get("yanger");
if (pre == null) {
map.put("yanger", current);
} else if (pre != null && current > pre) {
progressManager.getMap().put("yanger", current);
}
lock.unlock();
}
countDownLatch.countDown();
}
});
}
countDownLatch.await();
if (stringBuffer.length() > 0) {
throw new SqoopException(stringBuffer.toString() + "導入失敗");
}
return flag==0?true:false;
}
sqoop 相關配置
public static String[] importFile(ImportModel sqlModel,int threadCount, Long max, Long min) {
Integer model=sqlModel.getImportModel();
List<String> list = new ArrayList<String>();
list.add("--connect"); //數據庫url
list.add(sqlModel.getUrl()+ "?serverTimezone=GMT%2B8&useUnicode=true&defaultFetchSize=10000&characterEncoding=utf-8");
list.add("--driver"); //數據庫驅動
list.add(sqlModel.getDriver());
list.add("--username"); //數據庫賬號
list.add(sqlModel.getUsername());
list.add("--password"); //數據庫密碼
list.add(sqlModel.getPassword());
list.add("--table"); //指定導入的表
list.add(sqlModel.getTable());
list.add("--bindir"); //指定生成jar的路徑
list.add("lib");
list.add("--fetch-size"); //批量讀取
list.add("10000");
list.add("--target-dir"); //指定導入到那個HDFS文件中
list.add("/TestMill");
list.add("--outdir"); //指定生成類的路徑
list.add("lib");
list.add("--fields-terminated-by"); //分割符
list.add(",");
list.add("--skip-dist-cache"); //分佈式緩存
list.add("--direct");
list.add("-m");
list.add("10");
if (model!=null && model == 2) {
list.add("--incremental"); //增量導入
list.add("lastmodified");
}else {
list.add("--incremental"); //增量導入
list.add("append");
}
if (threadCount==1) {
list.add("--where");
list.add("id<" + sqlModel.getLine());
}else{
if(sqlModel.getLine()<max)
max=sqlModel.getLine();
list.add("--where");
list.add("id<="+max+" and id >"+min);
}
if (sqlModel.getColmun() == null||sqlModel.getColmun() == "" ) {
//如果沒有指定列,默認自增指定id
list.add("--check-column");
list.add("id");
}else {
list.add("--check-column"); //導入時要檢查的列
list.add(sqlModel.getColmun());
list.add("--split-by");
list.add(sqlModel.getColmun());
}
return list.toArray(new String[list.size()]);
}