最近公司有个需求要让我使用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()]);
}