Hadoop和关系型数据库间的数据传输工具——Sqoop
Hadoop和關系型數(shù)據(jù)庫間的數(shù)據(jù)傳輸工具——Sqoop
一、Sqoop簡介以及使用
1.1、產(chǎn)生背景
基于傳統(tǒng)關系型數(shù)據(jù)庫的穩(wěn)定性,還是有很多企業(yè)將數(shù)據(jù)存儲在關系型數(shù)據(jù)庫中;早期由于工具的缺乏,Hadoop與傳統(tǒng)數(shù)據(jù)庫之間的數(shù)據(jù)傳輸非常困難。基于前兩個方面的考慮,需要一個在傳統(tǒng)關系型數(shù)據(jù)庫和Hadoop之間進行數(shù)據(jù)傳輸?shù)捻椖?#xff0c;Sqoop應運而生。1.2、Sqoop是什么
Sqoop是一個用于Hadoop和結構化數(shù)據(jù)存儲(如關系型數(shù)據(jù)庫)之間進行高效傳輸大批量數(shù)據(jù)的工具。它包括以下兩個方面:
- 可以使用Sqoop將數(shù)據(jù)從關系型數(shù)據(jù)庫管理系統(tǒng)(如MySQL)導入到Hadoop系統(tǒng)(如HDFS、Hive、HBase)中
- 將數(shù)據(jù)從Hadoop系統(tǒng)中抽取并導出到關系型數(shù)據(jù)庫(如MySQL)
常見數(shù)據(jù)庫開源工具:
1.3、底層實現(xiàn)原理
? Sqoop的核心設計思想是利用MapReduce加快數(shù)據(jù)傳輸速度。也就是說Sqoop的導入和導出功能是通過基于Map Task(只有map)的MapReduce作業(yè)實現(xiàn)的。所以它是一種批處理方式進行數(shù)據(jù)傳輸,難以實現(xiàn)實時的數(shù)據(jù)進行導入和導出。
官網(wǎng)介紹:
Apache Sqoop? is a tool designed for efficiently transferring bulk
data between Apache Hadoop and structured datastores such as relational databases.
Sqoop結構圖:
1.4、特點
- 優(yōu)點:它可以將跨平臺的數(shù)據(jù)進行整合。
- 缺點:它不是很靈活。
主要執(zhí)行操作
#mermaid-svg-GlkoSBcpbHzyZ0FK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .error-icon{fill:#552222;}#mermaid-svg-GlkoSBcpbHzyZ0FK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GlkoSBcpbHzyZ0FK .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-GlkoSBcpbHzyZ0FK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GlkoSBcpbHzyZ0FK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GlkoSBcpbHzyZ0FK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GlkoSBcpbHzyZ0FK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GlkoSBcpbHzyZ0FK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .marker.cross{stroke:#333333;}#mermaid-svg-GlkoSBcpbHzyZ0FK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GlkoSBcpbHzyZ0FK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GlkoSBcpbHzyZ0FK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-GlkoSBcpbHzyZ0FK .actor-line{stroke:grey;}#mermaid-svg-GlkoSBcpbHzyZ0FK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .sequenceNumber{fill:white;}#mermaid-svg-GlkoSBcpbHzyZ0FK #sequencenumber{fill:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .messageText{fill:#333;stroke:#333;}#mermaid-svg-GlkoSBcpbHzyZ0FK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GlkoSBcpbHzyZ0FK .labelText,#mermaid-svg-GlkoSBcpbHzyZ0FK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-GlkoSBcpbHzyZ0FK .loopText,#mermaid-svg-GlkoSBcpbHzyZ0FK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-GlkoSBcpbHzyZ0FK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-GlkoSBcpbHzyZ0FK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-GlkoSBcpbHzyZ0FK .noteText,#mermaid-svg-GlkoSBcpbHzyZ0FK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-GlkoSBcpbHzyZ0FK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GlkoSBcpbHzyZ0FK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GlkoSBcpbHzyZ0FK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GlkoSBcpbHzyZ0FK .actorPopupMenu{position:absolute;}#mermaid-svg-GlkoSBcpbHzyZ0FK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-GlkoSBcpbHzyZ0FK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GlkoSBcpbHzyZ0FK .actor-man circle,#mermaid-svg-GlkoSBcpbHzyZ0FK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-GlkoSBcpbHzyZ0FK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}MysqlHDFSHiveHBaseimportimportimportexportexportMysqlHDFSHiveHBasesqoop的重要的幾個關鍵詞
- import : 從關系型數(shù)據(jù)庫到hadoop
- export : 從hadoop到關系型數(shù)據(jù)庫。
二、Sqoop的安裝
注意:在安裝sqoop之前要配置好本機的Java環(huán)境和Hadoop環(huán)境
先把spoop的安裝包sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz拷貝在系統(tǒng)目錄下的 /root/soft下面
2.1、解壓配置環(huán)境變量
# 解壓tar.gz包 [root@master local] tar -zxvf /root/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /usr/local/#把sqoop的安裝路徑修改為sqoop,方便以后配置和調用 [root@master local]# mv sqoop-1.4.7.bin__hadoop-2.6.0 sqoop [root@master sqoop]# vim /etc/profile # 追加內(nèi)容如下:export SQOOP_HOME=/usr/local/sqoop export PATH=$SQOOP_HOME/bin:$PATH2.2、新建配置文件
[root@master sqoop] mv ./conf/sqoop-env-template.sh ./conf/sqoop-env.sh2.3、修改配置文件
配置文件:
[root@master sqoop] vim ./conf/sqoop-env.sh按照本系統(tǒng)實際安裝的Hadoop系列目錄配置好下面的路徑:
export HADOOP_COMMON_HOME=/usr/local/hadoop export HADOOP_MAPRED_HOME=/usr/local/hadoop export HIVE_HOME=/usr/local/hive export ZOOCFGDIR=/usr/local/zookeeper2.4、拷貝mysql驅動
因為我們現(xiàn)在通過JDBC讓Mysql和HDFS等進行數(shù)據(jù)的導入導出,所以我們先必須把JDBC的驅動包拷貝到sqoop/lib路徑下,如下
[root@master sqoop] cp /root/mysql-connector-java-5.1.18.jar ./lib/2.5、驗證安裝:
#查看sqoop的版本 [root@master sqoop] sqoop version三、Sqoop命令執(zhí)行
3.1、常見命令執(zhí)行參數(shù)
通過sqoop加不同參數(shù)可以執(zhí)行導入導出,通過sqoop help 可以查看常見的命令行
#常見sqoop參數(shù) [root@master sqoop] sqoop helpcodegen Generate code to interact with database recordscreate-hive-table Import a table definition into Hiveeval Evaluate a SQL statement and display the resultsexport Export an HDFS directory to a database table #導出help List available commandsimport Import a table from a database to HDFS #導入import-all-tables Import tables from a database to HDFSimport-mainframe Import mainframe datasets to HDFSlist-databases List available databases on a serverlist-tables List available tables in a databaseversion Display version information3.2、直接執(zhí)行命令
Sqoop運行的時候不需要啟動后臺進程,直接執(zhí)行sqoop命令加參數(shù)即可.簡單舉例如下:
# #通過參數(shù)用下面查看數(shù)據(jù)庫 [root@master sqoop] sqoop list-databases --connect jdbc:mysql://node2:3306 --username root --password 123123;3.3、通過文件傳遞參數(shù)(腳本)
在執(zhí)行sqoop命令時,如果每次執(zhí)行的命令都相似,那么把相同的參數(shù)可以抽取出來,放在一個文本文件中,把執(zhí)行時的參數(shù)加入到這個文本文件為參數(shù)即可. 這個文本文件可以用--options-file來指定,平時可以用定時任務來執(zhí)行這個腳本,避免每次手工操作.
把3.2章節(jié)中命令中的jdbc連接的參數(shù)一般是不變的,可以把它抽取出來放在一個文件中/.../sqoop/config.conf,如下:
list-databases --connect jdbc:mysql://localhost:3306 --username root --password 123123那么上面的執(zhí)行的命令就可以變?yōu)?
[root@master sqoop] bin/sqoop --options-file config.conf為了讓配置文件config.txt的可讀性更強,可以加入空行和注釋,不會影響文件內(nèi)容的讀取,如下:
# 指令: 列出mysql中的所有數(shù)據(jù)庫 list-databases# 指定連接字符串 --connect jdbc:mysql://localhost:3306--username root--password 1231233.4、Import 詳解
import是從關系數(shù)據(jù)庫導入到Hadoop,下面是一些通用參數(shù)介紹:
3.4.1、通用參數(shù)
如下:
| –connect | 指定JDBC連接字符串 |
| --connection-manager | 指定連接管理類 |
| --driver | 指定連接的驅動程序 |
| -P | 從控制臺讀入密碼(可以防止密碼顯示中控制臺) |
| –password | 指定訪問數(shù)據(jù)庫的密碼 |
| –username | 指定訪問數(shù)據(jù)庫的用戶名 |
3.4.1.1、連接數(shù)據(jù)庫
sqoop的設計就是把數(shù)據(jù)庫數(shù)據(jù)導入HDFS,所以必須指定連接字符串才能訪問數(shù)據(jù)庫,這個連接字符串類似于URL,這個連接字符串通過--connect參數(shù)指定,它描述了連接的數(shù)據(jù)庫地址和具體的連接數(shù)據(jù)庫,譬如:
#指定連接的服務器地址是database.example.com ,要連接的數(shù)據(jù)庫是employees [root@master sqoop] sqoop import --connect jdbc:mysql://database.example.com/employees上面連接命令只是指定數(shù)據(jù)庫,默認情況下數(shù)據(jù)庫都是需要用戶名和參數(shù)的,在這里可以用--username 和--password來指定,譬如:
#指定用戶名和密碼來連接數(shù)據(jù)庫 [root@master sqoop] sqoop import --connect jdbc:mysql://localhost:3306/mysql --username root --password 123123;3.4.1.2、查看數(shù)據(jù)庫
在Sqoop中,可以通過list-databases參數(shù)來查看mysql的數(shù)據(jù)庫,這樣在導入之前可以得到所有的數(shù)據(jù)庫的名字,具體案例如下:
# 列出所有數(shù)據(jù)庫 [root@master sqoop] bin/sqoop list-databases --connect jdbc:mysql://localhost:3306 --username root --password 123123;3.4.1.3、查看所有表
在得到所有數(shù)據(jù)庫的名字后,也可以查看當前數(shù)據(jù)庫中的所有表,可以使用 list-tables參數(shù)來進行查看,查看的時候在url連接中一定要指定數(shù)據(jù)庫的名字.
# 列出數(shù)據(jù)庫中所有表 [root@master sqoop] bin/sqoop list-tables --connect jdbc:mysql://node2:3306/qfdb --username root --password 123123;3.4.2、Import的控制參數(shù)
常見Import的控制參數(shù)有如下幾個:
| --append | 通過追加的方式導入到HDFS |
| --as-avrodatafile | 導入為 Avro Data 文件格式 |
| --as-sequencefile | 導入為 SequenceFiles文件格式 |
| --as-textfile | 導入為文本格式 (默認值) |
| --as-parquetfile | 導入為 Parquet 文件格式 |
| --columns | 指定要導入的列 |
| --delete-target-dir | 如果目標文件夾存在,則刪除 |
| --fetch-size | 一次從數(shù)據(jù)庫讀取的數(shù)量大小 |
| -m,--num-mappers | n 用來指定map tasks的數(shù)量,用來做并行導入 |
| -e,--query | 指定要查詢的SQL語句 |
| --split-by | 用來指定分片的列 |
| --table | 需要導入的表名 |
| --target-dir | HDFS 的目標文件夾 |
| --where | 用來指定導入數(shù)據(jù)的where條件 |
| -z,--compress | 是否要壓縮 |
| --compression-codec | 使用Hadoop壓縮 (默認是 gzip) |
3.4.2.1、指定表導入
數(shù)據(jù)準備
在本地mysql數(shù)據(jù)庫中新建一個qfdb數(shù)據(jù)庫,sql代碼在data/qfdb.sql中,如下:
CREATE TABLE emp(empno INT primary key,ename VARCHAR(50),job VARCHAR(50),mgr INT,hiredate DATE,sal DECIMAL(7,2),comm decimal(7,2),deptno INT ) ; INSERT INTO emp values(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20); INSERT INTO emp values(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30); INSERT INTO emp values(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30); INSERT INTO emp values(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20); INSERT INTO emp values(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30); INSERT INTO emp values(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30); INSERT INTO emp values(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10); INSERT INTO emp values(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20); INSERT INTO emp values(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10); INSERT INTO emp values(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30); INSERT INTO emp values(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20); INSERT INTO emp values(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30); INSERT INTO emp values(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20); INSERT INTO emp values(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);sqoop的典型導入都是把關系數(shù)據(jù)庫中的表導入到HDFS中,使用--table參數(shù)可以指定具體的表導入到hdfs,譬如用 --table emp,默認情況下是全部字段導入.如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp \ --target-dir hdfs://master:9000/sqoopdata/emp --delete-target-dir可以快速使用hdfs的命令查詢結果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*3.4.2.2、指定列導入
如果想導入某幾列,可以使用 --columns,如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp \ --columns 'empno,mgr' \ --target-dir hdfs://master:9000/sqoopdata/emp \ --delete-target-dir可以使用下面hdfs命令快速查看結果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*3.4.2.3、指定條件導入
在導入表的時候,也可以通過指定where條件來導入,具體參數(shù)使用 --where,譬如要導入員工號大于7800的記錄,可以用下面參數(shù):
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp \ --columns 'empno,mgr' \ --where 'empno>7800' \ --target-dir hdfs://master:9000/sqoopdata/5 \ --delete-target-dir用命令查詢結果:
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*結果如下:
7839,null 7844,7698 7876,7788 7900,7698 7902,7566 7934,77823.4.2.4、指定Sql導入
上面的可以通過表,字段,條件進行導入,但是還不夠靈活,其實sqoop還可以通過自定義的sql來進行導入,可以通過--query 參數(shù)來進行導入,這樣就最大化的用到了Sql的靈活性。如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \ --target-dir hdfs://master:9000/sqoopdata/emp \ --delete-target-dir \ --split-by empno \ -m 1注意:在通過--query來導入數(shù)據(jù)時,必須要指定--target-dir
如果你想通過并行的方式導入結果,每個map task需要執(zhí)行sql查詢語句的副本,結果會根據(jù)sqoop推測的邊界條件分區(qū)。query必須包含$CONDITIONS。這樣每個scoop程序都會被替換為一個獨立的條件。同時你必須指定--split-by。分區(qū) -m 1 是指定通過一個Mapper來執(zhí)行流程
查詢執(zhí)行結果
[root@master sqoop]# hdfs dfs -cat /sqoopdata/emp/par*結果如下:
7839,null,PRESIDENT 7844,7698,SALESMAN 7876,7788,CLERK 7900,7698,CLERK 7902,7566,ANALYST 7934,7782,CLERK3.4.2.5、單雙引號區(qū)別
在導入數(shù)據(jù)時,默認的字符引號是單引號,這樣sqoop在解析的時候就安裝字面量來解析,不會做轉移:例如:
--query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \如果使用了雙引號,那么Sqoop在解析的時候會做轉義的解析,這時候就必須要加轉義字符 \ 如下:
--query "select empno,mgr,job from emp WHERE empno>7800 and \$CONDITIONS" \3.4.2.6、MySql缺主鍵問題
1、如果mysql的表沒有主鍵,將會報錯:
19/12/02 10:39:50 ERROR tool.ImportTool: Import failed: No primary key could be found for table u1. Please specify one with -- split-by or perform a sequential import with '-m 1'解決方案:
通過 --split-by 來指定要分片的列代碼如下:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --query 'select empno,mgr,job from emp WHERE empno>7800 and $CONDITIONS' \ --target-dir hdfs://master:9000/sqoopdata/emp \ --delete-target-dir \ --split-by empno \ -m 13.4.3、導入到Hive中
3.4.3.1、說明
? Sqoop的導入工具的主要功能是將數(shù)據(jù)上傳到HDFS中的文件中。如果您有一個與HDFS集群相關聯(lián)的Hive,Sqoop還可以通過生成和執(zhí)行CREATETABLE語句來定義Hive中的數(shù)據(jù),從而將數(shù)據(jù)導入到Hive中。將數(shù)據(jù)導入到Hive中就像在Sqoop命令行中添加–hive-import選項。
? 如果Hive表已經(jīng)存在,則可以指定--hive-overwrite選項,以指示必須替換單元中的現(xiàn)有表。在將數(shù)據(jù)導入HDFS或省略此步驟之后,Sqoop將生成一個Hive腳本,其中包含使用Hive的類型定義列的CREATE表操作,并生成LOAD Data INPATH語句將數(shù)據(jù)文件移動到Hive的倉庫目錄中。
在導入Hive之前先要配置Hadoop的Classpath才可以,否則會報類找不到錯誤,在/etc/profile末尾添加如下配置:
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HIVE_HOME/lib/*#刷新配置 source /etc/profile3.4.3.2、參數(shù)說明
具體的參數(shù)如下:
| --hive-home | 覆蓋環(huán)境配置中的$HIVE_HOME,默認可以不配置 |
| –hive-import | 指定導入數(shù)據(jù)到Hive中 |
| --hive-overwrite | 覆蓋當前已有的數(shù)據(jù) |
| --create-hive-table | 是否創(chuàng)建hive表,如果已經(jīng)存在,則會失敗 |
| --hive-table | 設置要導入的Hive中的表名 |
3.4.3.3、實際導入案例
具體導入演示代碼如下:
提示: 為了看到演示效果,可以先在Hive刪除emp表
[root@master sqoop] bin/sqoop import --connect jdbc:mysql://node2:3306/qfdb \ --username root \ --password 123123 \ --table emp \ --hive-import \ --hive-overwrite \ --fields-terminated-by ',' \ -m 1在Hive中查看表:
hive> show tables; #結果如下: OK emp可以在Hive中查看數(shù)據(jù)是否導入:
select * from emp; #結果如下: 7369 SMITH CLERK 7902 1980-12-17 800.0 NULL 20 7499 ALLEN SALESMAN 7698 1981-02-20 1600.0 300.0 30 7521 WARD SALESMAN 7698 1981-02-22 1250.0 500.0 30 7566 JONES MANAGER 7839 1981-04-02 2975.0 NULL 20 7654 MARTIN SALESMAN 7698 1981-09-28 1250.0 1400.0 30 7698 BLAKE MANAGER 7839 1981-05-01 2850.0 NULL 30 7782 CLARK MANAGER 7839 1981-06-09 2450.0 NULL 10 7788 SCOTT ANALYST 7566 1987-04-19 3000.0 NULL 20 7839 KING PRESIDENT NULL 1981-11-17 5000.0 NULL 10 7844 TURNER SALESMAN 7698 1981-09-08 1500.0 0.0 30 7876 ADAMS CLERK 7788 1987-05-23 1100.0 NULL 20 7900 JAMES CLERK 7698 1981-12-03 950.0 NULL 30 7902 FORD ANALYST 7566 1981-12-03 3000.0 NULL 20 7934 MILLER CLERK 7782 1982-01-23 1300.0 NULL 10四、Sqoop導入實戰(zhàn)
4.1、Sqoop-import
案例1
表沒有主鍵,需要指定map task的個數(shù)為1個才能執(zhí)行
Sqoop導入原理:
? Sqoop默認是并行的從數(shù)據(jù)庫源導入數(shù)據(jù)。您可以使用-m或–num-mappers參數(shù)指定用于執(zhí)行導入的map任務(并行進程)的數(shù)量。每個參數(shù)都取一個整數(shù)值,該整數(shù)值對應于要使用的并行度。默認情況下,使用四個任務。一些數(shù)據(jù)庫可以通過將這個值增加到8或16來改善性能。
? 默認情況下,Sqoop將標識表中的主鍵id列用作拆分列。從數(shù)據(jù)庫中檢索分割列的高值和低值,map任務操作整個范圍的大小均勻的組件。譬如ID的范圍是0-800,那么Sqoop默認運行4個進程,通過執(zhí)行 SELECT MIN(id), MAX(id) FROM emp找出id的范圍,然后把4個任務的id設置范圍是(0-200),(200-400),(400-600),(600-800)
但是當一個表沒有主鍵時,上面的切分就無法進行,sqoop導入時就會出錯,這時候可以通過-m把mapper的數(shù)量設為1,只有也Mapper在運行,這時候就不需要切分,也可以避免主鍵不存在時候報錯的問題.
#錯誤信息 ERROR tool.ImportTool: Import failed: No primary key could be found for table emp. Please specify one with --split-by or perform a sequential import with '-m 1'.導入代碼:
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp -m 14.2、DBMS-HDFS
案例2
表沒有主鍵,使用–split-by指定執(zhí)行split的字段
問題同上,如果表沒有主鍵,那么還有個辦法就是手工指定要拆分的列,通過--split-by來指定
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp \ --split-by empno \ --delete-target-dir \ --target-dir hdfs://master:9000/sqoopdata/emp -- 出錯 Caused by: java.sql.SQLException: null, message from server: "Host 'master' is not allowed to connect to this MySQL server"解決方案:
先連接mysql:
[root@master sqoop]# mysql -uroot -p(執(zhí)行下面的語句 .:所有庫下的所有表 %:任何IP地址或主機都可以連接)
mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY 'mysql' WITH GRANT OPTION;FLUSH PRIVILEGES;grant all privileges on . to root@"localhost" identified by "mysql" with grant option;FLUSH PRIVILEGES;案例3:條件導入
需要導入的數(shù)據(jù)不是全部的,而是帶條件導入
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --table emp \ --split-by empno \ --where 'empno > 7777' \ --target-dir hdfs://master:9000/sqoopdata/emp案例4:部分字段導入
:要導入的數(shù)據(jù),不想包含全部字段,只需要部分字段
[root@master sqoop] bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb \ --username root --password 123123 \ --split-by empno \ --query 'select empno,ename,job from emp where empno > 7777 and $CONDITIONS' \ --target-dir hdfs://master:9000/sqoopdata/74.3、DBMS-Hive
案例5:將數(shù)據(jù)導入到hive中
[root@master sqoop]# bin/sqoop import --connect jdbc:mysql://localhost:3306/qfdb --username root --password 123123 --table emp --hive-import -m 1五、Sqoop導出
在Sqoop中,使用export進行導出,指的是從HDFS中導出數(shù)據(jù)到Mysql中:
1、構建mysql的表:
CREATE TABLE `u2` (`id` int(11) DEFAULT NULL,`age` int(11) DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `u3` (`id` int(11) DEFAULT NULL,`name` varchar(20) default NULL,`age` int(11) DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8;2、HDFS導出到mysql
[root@master sqoop]# sqoop export --connect jdbc:mysql://master:3306/qfdb \ --username root \ --password root \ --table u2 \ --driver com.mysql.jdbc.Driver \ --export-dir '/1906sqoop/u2/*' \ -m 1# 方法二: 先重新導入數(shù)據(jù): [root@master sqoop]# sqoop import --connect jdbc:mysql://master:3306/qfdb \ --username root \ --password root \ --query 'select id,name,age from stu where id > 6 and $CONDITIONS' \ --driver com.mysql.jdbc.Driver \ --delete-target-dir \ --target-dir '/1906sqoop/u7' \ --split-by id \ -m 1 \ --fields-terminated-by '\t' \ --null-string '\\N' \ --null-non-string '0'導出語句: [root@master sqoop]# sqoop export --connect jdbc:mysql://hadoop01:3306/qfdb \ --username root \ --password root \ --table u3 \ --driver com.mysql.jdbc.Driver \ --export-dir '/1906sqoop/u7/*' \ --input-fields-terminated-by '\t' \ --input-null-string '\\N' \ --input-null-non-string '\\N' \ -m 1要注意以下問題
- mysql表的編碼格式做為utf8,hdfs文件中的列數(shù)類型和mysql表中的字段數(shù)一樣
- 導出暫不能由hbase表導出mysql關系型數(shù)據(jù)庫中
- --export-dir是一個hdfs中的目錄,它不識別_SUCCESS文件
- –query導入的時候注意設置問題。
- 導出數(shù)據(jù)中有些列值有"null",會報沒法解析
- 導出數(shù)據(jù)的類型需要和mysql中的一致(能自動轉沒有問題)
六、Sqoop的Job
6.1、增量導入數(shù)據(jù)
6.1.1、使用場景
6.1.2、使用方式
- query where : 能精確鎖定數(shù)據(jù)范圍
- –incremental : 增量,最后記錄值來做的
6.1.2.1、query where方式
通過查詢具體日期的方式進行導入
新建一個腳本文件
[root@hadoop01 sqoop-1.4.7] vim ./import.sh寫入以下內(nèi)容:
#!/bin/bash # yesterday=`date -d "1 days ago" "+%Y-%m-%d"` yesterday='2022-02-01' sqoop import --connect jdbc:mysql://master:3306/sales_source \ --username root \ --password 123123 \ --query "select * from sales_order where DATE(order_date) = '${yesterday}' and \$CONDITIONS" \ --driver com.mysql.jdbc.Driver \ --delete-target-dir \ --target-dir /user/hive/warehouse/sales_order/dt=${yesterday} \ --split-by id \ -m 1 \ --fields-terminated-by '\t' \ --null-string '\\N' \ --null-non-string '0'通過下面hdfs可以快速查詢到結果:
[root@hadoop01 sqoop-1.4.7]# hdfs dfs -cat /user/hive/warehouse/sales_order/dt=2019-01-01/pa*6.1.2.2 increment的append方式:
#將會手動維護last-value [root@hadoop01 sqoop-1.4.7]# sqoop import --connect jdbc:mysql://master:3306/sales_source \ --username root \ --password root \ --table sales_order \ --driver com.mysql.jdbc.Driver \ --target-dir /user/hive/warehouse/sales_order1/dt=2019-12-30 \ --split-by id \ -m 1 \ --check-column order_number \ --incremental append \ --last-value 80000 \ --fields-terminated-by '\t' \ --null-string '\\N' \ --null-non-string '0'使用下面命令查看:
[root@hadoop01 sqoop-1.4.7]# hdfs dfs -cat /user/hive/warehouse/sales_order1/dt=2019-12-30/pa*6.2、Job操作
job的好處:
sqoop提供一系列的job語句來操作sqoop。
$ sqoop job (generic-args) (job-args) [-- [subtool-name] (subtool-args)] $ sqoop-job (generic-args) (job-args) [-- [subtool-name] (subtool-args)]使用方法:
usage: sqoop job [GENERIC-ARGS] [JOB-ARGS] [-- [<tool-name>] [TOOL-ARGS]]Job management arguments:--create <job-id> Create a new saved job--delete <job-id> Delete a saved job--exec <job-id> Run a saved job--help Print usage instructions--list List saved jobs--meta-connect <jdbc-uri> Specify JDBC connect string for the metastore--show <job-id> Show the parameters for a saved job--verbose Print more information while working列出sqoop的job:
[root@master sqoop] sqoop job --list創(chuàng)建一個sqoop的job:
[root@master sqoop]# sqoop job --create job1 -- import --connect jdbc:mysql://master:3306/qfdb \ --username root \ --password root \ --table u2 \ --driver com.mysql.jdbc.Driver \ --delete-target-dir \ --target-dir '/sqoop/job/job1' \ --split-by id \ -m 1執(zhí)行sqoop的job:
#如報錯json包找不到,則需要手動添加 sqoop job --exec job1執(zhí)行的時候回讓輸入密碼: 輸入該節(jié)點用戶的對應的密碼即可 # 1、配置客戶端記住密碼(sqoop-site.xml)追加 <property><name>sqoop.metastore.client.record.password</name><value>true</value> </property># 2、將密碼配置到hdfs的某個文件,我們指向該密碼文件 說明:在創(chuàng)建Job時,使用--password-file參數(shù),而且非--passoword。主要原因是在執(zhí)行Job時使用--password參數(shù)將有警告,并且需要輸入密碼才能執(zhí)行Job。當我們采用--password-file參數(shù)時,執(zhí)行Job無需輸入數(shù)據(jù)庫密碼。 [root@master sqoop]# echo -n "root" > sqoop.pwd [root@master sqoop]# hdfs dfs -rm sqoop.pwd /input/sqoop.pwd [root@master sqoop]# hdfs dfs -put sqoop.pwd /input [root@master sqoop]# hdfs dfs -chmod 400 /input/sqoop.pwd [root@master sqoop]# hdfs dfs -ls /input -r-------- 1 hadoop supergroup 6 2018-01-15 18:38 /input/sqoop.pwd查看sqoop的job:
[root@master sqoop] sqoop job --show sq1刪除sqoop的job:
[root@master sqoop] sqoop job --delete sq1問題:
1、創(chuàng)建job報錯:19/12/02 23:29:17 ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.NullPointerException java.lang.NullPointerExceptionat org.json.JSONObject.<init>(JSONObject.java:144)解決辦法: 添加java-json.jar包到sqoop的lib目錄中。 如果上述辦法沒有辦法解決,請注意hcatlog的版本是否過高,過高將其hcatlog包剔除sqoop的lib目錄即可。2、報錯:Caused by: java.lang.ClassNotFoundException: org.json.JSONObject 解決辦法: 添加java-json.jar包到sqoop的lib目錄中。6.3、metastore服務
metastore服務是元數(shù)據(jù)服務,用于存儲sqoop的job相關信息,將信息保存于關系型數(shù)據(jù)庫中。
優(yōu)點:
(1)在MySQL中創(chuàng)建Sqoop的元數(shù)據(jù)存儲數(shù)據(jù)庫 (如果有root可以用root)
create database sqoop; create user 'sqoop'@'%' identified by 'sqoop'; grant all privileges on sqoop.* to 'sqoop'@'%'; flush privileges;(2)配置Sqoop的元數(shù)據(jù)存儲參數(shù)
? 在$SQOOP_HOME/conf/sqoop-site.xml中添加以下的參數(shù),在/code/sqoop-site.xml也可以查閱。
sqoop.metastore.server.location:指定元數(shù)據(jù)服務器位置,初始化建表時需要。 sqoop.metastore.client.autoconnect.url:客戶端自動連接的數(shù)據(jù)庫的URL。 sqoop.metastore.client.autoconnect.username:連接數(shù)據(jù)庫的用戶名。 sqoop.metastore.client.enable.autoconnect:啟用客戶端自動連接數(shù)據(jù)庫。 sqoop.metastore.client.record.password:在數(shù)據(jù)庫中保存密碼,不需要密碼即可執(zhí)行sqoop job腳本。 sqoop.metastore.client.autoconnect.password:連接數(shù)據(jù)庫的密碼。<property><name>sqoop.metastore.client.enable.autoconnect</name><value>false</value><description>If true, Sqoop will connect to a local metastorefor job management when no other metastore arguments areprovided.</description></property><property><name>sqoop.metastore.client.autoconnect.url</name><value>jdbc:mysql://192.168.10.103:3306/sqoop</value></property><property><name>sqoop.metastore.client.autoconnect.username</name><value>root</value></property><property><name>sqoop.metastore.client.autoconnect.password</name><value>123456</value></property><property><name>sqoop.metastore.client.record.password</name><value>true</value></property><property><name>sqoop.metastore.server.location</name><value>/usr/local/sqoop/sqoop-metastore/shared.db</value></property><property><name>sqoop.metastore.server.port</name><value>16000</value></property>(3)重啟Sqoop服務
? 保存配置并重啟完成后,MySQL的sqoop庫中有了一個名為SQOOP_ROOT的空表。
#啟動: [root@master sqoop]# sqoop metastore &#查看進程: [root@master sqoop]# jps sqoop#關閉: [root@master sqoop]# sqoop metastore --shutdown(4)預裝載SQOOP表
insert into SQOOP_ROOT values (NULL, 'sqoop.hsqldb.job.storage.version', '0');(5)job相關操作
[root@master sqoop]# sqoop job --list ###需要加--meta-connect創(chuàng)建job: [root@master sqoop]# sqoop job --create sq3 --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' -- import --connect jdbc:mysql://hadoop01:3306/test \ --username root \ --password root \ --table user_info \ --driver com.mysql.jdbc.Driver \ --delete-target-dir \ --target-dir '/1906sqoop/u9' \ --split-by id \ -m 1列出job: [root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --list執(zhí)行job: [root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --exec sq3執(zhí)行job并打印詳細信息: [root@master sqoop]# sqoop job --meta-connect 'jdbc:mysql://master:3306/sqoop?user=root&password=root' --exec sq3 -verbose? 此時并不會返回先前已經(jīng)創(chuàng)建的myjob_incremental_import作業(yè),因為此時MySQL中沒有元數(shù)據(jù)信息。該命令執(zhí)行完成后,MySQL的sqoop庫中有了一個名為SQOOP_SESSIONS的空表,該表存儲sqoop job相關信息。
(6)將表的存儲引擎修改為MYISAM(如job信息存儲到mysql的SQOOP_SESSIONS則不用執(zhí)行如下)
alter table SQOOP_ROOT engine=myisam; alter table SQOOP_SESSIONS engine=myisam;因為每次執(zhí)行增量抽取后都會更新last_value值,如果使用Innodb可能引起事務鎖超時錯誤。
七、Sqoop優(yōu)化
7.1、-m與split-by的優(yōu)化
7.2、 --fetch-size n
一次取mysq1中批量讀取的數(shù)據(jù)條數(shù)。建議優(yōu)化如下:
總結
以上是生活随笔為你收集整理的Hadoop和关系型数据库间的数据传输工具——Sqoop的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据能破案 从数据库侦查出新证据
- 下一篇: 实用经济学术语