sqoop使用入門


sqoop是apache旗下,用於關系型數據庫和hadoop之間傳輸數據的工具,sqoop可以用在離線分析中,將保存在mysql的業務數據傳輸到hive數倉,數倉分析完得到結果,再通過sqoop傳輸到mysql,最后通過web+echart來進行圖表展示,更加直觀的展示數據指標。

sqoop基礎

基本概念

如下圖所示,sqoop中有導入和導出的概念,參照物都是hadoop文件系統,其中關系型數據庫可以是mysql、oracle和db2,hadoop文件系統中可以是hdfs、hive和hbase等。執行sqoop導入和導出,其本質都是轉化成了mr任務去執行。

 

基本架構

目前sqoop提供了兩個版本,1.4.x的為sqoop1,1.99x的為sqoop2,前者因為安裝簡單,得到了大量使用,后者雖然引進了安全機制、web ui,rest api等更加方便使用的特性,但是安裝過程繁瑣暫時不記錄。

以下是sqoop1的結構圖,它只提供一個sqoop客戶端,使用命令行方式來執行導入/導出任務,最終任務都會被轉化為mr,實現數據在hdfs/hbase/hive和rdbms/企業數據倉庫之間的轉換。

sqoop安裝

sqoop的安裝相對簡單,只需選擇對應的sqoop解壓到安裝目錄即可,一般將sqoop安裝到已經安裝了mysql和hive的節點上。這里mysql版本為5.7.28,hive版本為cdh的1.1.0。

(1)解壓sqoop安裝包,sqoop版本為1.4.6。

[root@node01 /kkb/soft]# tar -zxvf sqoop-1.4.6-cdh5.14.2.tar.gz -C /kkb/install/

(2)修改sqoop根目錄/conf下的sqoop-env.sh文件,配置環境相關的參數。剛安裝后需要復制模版文件,命名為sqoop-env.sh,因為此次sqoop安裝后要實現關系型數據庫跟hadoop、hive和hbase的數據傳輸,因此在里面配置hadoop、hive和hbase的安裝路徑。

# Set Hadoop-specific environment variables here.

#Set path to where bin/hadoop is available
export HADOOP_COMMON_HOME=/kkb/install/hadoop-2.6.0-cdh5.14.2

#Set path to where hadoop-*-core.jar is available
export HADOOP_MAPRED_HOME=/kkb/install/hadoop-2.6.0-cdh5.14.2

#set the path to where bin/hbase is available
export HBASE_HOME=/kkb/install/hbase-1.2.0-cdh5.14.2

#Set the path to where bin/hive is available
export HIVE_HOME=/kkb/install/hive-1.1.0-cdh5.14.2

(3)復制數據庫驅動包到sqoop的lib目錄,如圖拷貝mysql-connector-java-5.1.38.jar和java-json.jar。

(4)配置sqoop環境變量,也可以不配置,直接進入sqoop的bin目錄下執行sqoop腳本也行。

sqoop使用

接下來使用安裝的sqoop,實現sqoop導入和導出,還可以創建sqoop job來完成作業,另外記錄。

下面可以使用sqoop來獲取數據庫的信息。

# list-databases獲取mysql中數據庫,list-tables可以查看某個數據庫下的表
[root@node01 /kkb/install/sqoop-1.4.6-cdh5.14.2/lib]# sqoop list-databases --connect jdbc:mysql://node01:3306 --username root --password 123456

導入數據到hdfs

(1)不指定導出目錄和分隔符。

mysql中提前准備好數據,測試導入到hdfs。使用dbeaver工具,在mysql中創建數據庫sqooptest,並建表Person,數據如下。

id|name  |age|score|position|
--|------|---|-----|--------|
 1|messi | 32|   55|前鋒      |
 2|herry | 40|   30|前鋒      |
 3|clyang| 33|    3|中場      |
 4|ronald| 35|   45|左前鋒     |

使用如下命令,將Person表中的數據import到hdfs。

# import 導入
# --connect 指定mysql連接地址,數據庫為sqooptest
# --username mysql用戶名
# --password mysql密碼
# --table 指定要導出的表Person
# --m 指定map task數,默認是4個
[hadoop@node01 ~]$ sqoop import --connect jdbc:mysql://node01:3306/sqooptest --username root --password 123456 --table Person --m 1

導出后提示保存了4條記錄,即剛才mysql中的四條數據。

導出到hdfs后,默認保存位置為/user/hadoop/數據庫表名,如下圖所示。查看導出的內容,發現跟mysql中的一致,並且字段值之間使用逗號隔開。

(2)指定導出目錄和分隔符,mysql中數據依然使用上面的,另外終端執行sqoop命令時可以使用反斜杠'\'轉義字符來隔開各個參數,類似終端中使用scala的豎線'|'。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \   
> --username root \
> --password 123456 \
> --table Person \
> --target-dir /sqoop/person \  # 指定導出目錄
> --delete-target-dir \ # 如果導出目錄存在,就先刪除
> --fields-terminated-by '\t' \  # 指定字段數據分隔符
> --m 1

導出后,進入指定目錄查看,發現成功導出到指定目錄,並用制表符分隔開。

(3)導入表的數據子集,可以通過指定where參數,將符合條件的子集導入到hdfs。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root --password 123456 \
> --table Person \
> --target-dir /sqoop/person_where \
> --delete-target-dir \
> --where "name = 'messi'" \ # where指定條件
> --m 1 

查看hdfs上數據,結果ok,只導出了name=messi的數據。

(4)可以使用--query,指定sql查詢條件過濾數據,再導入到hdfs。 

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --target-dir /sqoop/person_sql \
> --delete-target-dir \
> --query 'select * from Person where age>20 and $CONDITIONS' \ # 指定查詢條件,並添加$CONDITIONS變量
> --m 2

執行后,發現報錯,提示並行import時,需要指定split-by的字段。

重新指定split-by的字段為表的id字段,再次執行,ok。 

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --target-dir /sqoop/person_sql \
> --delete-target-dir \
> --query 'select * from Person where age>20 and $CONDITIONS' \ 
> --split-by 'id' \
> --m 2

查看hdfs,產生兩個maptask文件,可以看出是根據id分組后並行執行的結果。

(5)增量導入,有時候不需要導入表中的全部數據,只需要導入部分數據就可以。如增加行,就導入(append模式),或者某行時間戳有變化,就導入(lastmodified模式)。

append模式:

sqoop命令。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Person \
> --incremental append \ # append模式
> --check-column id \ # 檢查列為id列
> --last-value 4 \ # id列上一個記錄的值為4
> --target-dir /sqoop/increment \
> --m 1

mysql中添加一行數據,id為5,添加后執行上面的命令。

id|name  |age|score|position|
--|------|---|-----|--------|
 1|messi | 32|   55|前鋒      |
 2|herry | 40|   30|前鋒      |
 3|clyang| 33|    3|中場      |
 4|ronald| 35|   45|左前鋒     |
 5|kaka  | 45|    2|右前鋒     |

執行沒有報錯,查看hdfs中內容,發現只導入了新增id為5的這行數據。

lastmodified模式:

這個模式是基於時間列的增量數據導入,mysql中新准備一張包含時間列的表和數據,如下所示。

id|name  |salary|time               |
--|------|------|-------------------|
1 |clyang| 12000|2020-01-25 10:00:00|
2 |messi | 23000|2020-01-25 10:30:00|
3 |ronald| 22000|2020-01-25 10:45:00|
4 |herry | 21000|2020-01-25 11:15:00|

sqoop導入命令,使用lastmodified模式來導入新增數據。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Man \
> --incremental lastmodified \ # lasmodified模式
> --check column time \  # 檢查列為時間列
> --last-value '2020-01-25 10:00:00' \ # 指定上一個時間點
> --target-dir /sqoop/increment1 \
> --m 1

執行完成后,時間點在10點以后的數據,都導入到了hdfs。

現在對表的數據進行修改,新增並修改數據,測試能否導入。

# 修改id=4的salary為8888,並新增一列id=5
id
|name |salary|time | --|------|------|-------------------| 1 |clyang| 12000|2020-01-25 10:00:00| 2 |messi | 23000|2020-01-25 10:30:00| 3 |ronald| 22000|2020-01-25 10:45:00| 4 |herry | 8888|2020-01-25 11:15:00| 5 |kaka | 6666|2020-01-25 11:45:00|

sqoop命令,修改時間執行。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Man \
> --incremental lastmodified \ # lasmodified模式
> --check column time \  # 檢查列為時間列
> --last-value '2020-01-25 10:30:00' \ # 指定上一個時間點
> --target-dir /sqoop/increment1 \
> --m 1

執行后報錯,提示需要添加--append或-merge-key,因為導出目錄已經存在了。

20/02/06 11:16:34 ERROR tool.ImportTool: Import failed: --merge-key or --append is required when using --incremental lastmodified and the output directory exists.

命名添加--append后執行沒有報錯,查看目錄下內容。

繼續修改數據測試。

# 修改id為5的數據,並添加id為6的數據
id
|name |salary|time | --|-------|------|-------------------| 1 |clyang | 12000|2020-01-25 10:00:00| 2 |messi | 23000|2020-01-25 10:30:00| 3 |ronald | 22000|2020-01-25 10:45:00| 4 |herry | 8888|2020-01-25 11:15:00| 5 |kaka | 9999|2020-01-25 11:50:00| 6 |beckham| 23000|2020-01-25 12:00:00|

測試--merge-key的使用,sqoop命令行最后添加--merge-key id后執行沒有報錯。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Man \
> --incremental lastmodified \ # lasmodified模式
> --check column time \  # 檢查列為時間列
> --last-value '2020-01-25 10:30:00' \ # 指定上一個時間點
> --target-dir /sqoop/increment1 \
> --m 1
> --merge-key id

目錄下內容發現只有一個文件,並且sqoop里導出的時間在10:30以后,但依然有10點的數據在里面,說明經歷了reduce階段進行合並。

導入數據到hive

導出數據到hive前,需要將hive中的一個包(hive-exec-1.1.0-cdh5.14.2.jar)拷貝到sqoop的lib目錄。

[hadoop@node01 /kkb/install/hive-1.1.0-cdh5.14.2/lib]$ cp hive-exec-1.1.0-cdh5.14.2.jar /kkb/install/sqoop-1.4.6-cdh5.14.2/lib/

(1)手動創建hive表后導入

先手動在hive中建一個接收數據的表,這里指定的分隔符和sqoop導出時的分隔符要一致。

# 創建數據庫
hive (default)> create database sqooptohive;
OK
Time taken: 0.185 seconds
hive (default)> use sqooptohive;
OK
Time taken: 0.044 seconds
# 創建表
hive (sqooptohive)> create external table person(id int,name string,age int,score int,position string)row format delimited fields terminated by '\t';
OK
Time taken: 0.263 seconds
hive (sqooptohive)> show tables;
OK
tab_name
person

sqoop導出數據到hive表中。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Person \
> --fields-terminated-by '\t' \  # 這里需要和hive中分隔指定的一樣
> --delete-target-dir \
> --hive-import \  # 導入hive
> --hive-table sqooptohive.person \  #hive表
> --hive-overwrite \ # 覆蓋hive表中已有數據
> --m 1

查看hive表數據,發現導入ok。

(2)導入時自動創建hive表

 也可以不需要提前創建hive表,會自動創建。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Person \
> --hive-import \
> --hive-database sqooptohive \
> --hive-table person1 \
> --m 1

導入后,發現數據庫下多了一個表person1,查看數據ok。

導入數據到hbase

也可以將數據導入到hbase,依然使用sqooptest.Person表,導入前集群需啟動zookeeper和hbase。

sqoop命令

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table Person \
> --hbase-table mysqltohbase \ # 指定hbase表名
> --hbase-create-table \ # hbase沒有表就創建表
> --column-family f1 \ # 指定列族
> --hbase-row-key id \ # 執行rowkey
--m 1

執行完成后,hbase中查看發現新建了一張表,並且成功導入數據。

導出數據 

sqoop導出數據,這里記錄從hdfs導出數據,如果是hive導出,也是直接讀取hdfs保存目錄中的文件進行導出,比較類似。

hdfs中先准備數據

[hadoop@node01 ~]$ hadoop fs -cat /hdfstomysql.txt
20/02/06 14:31:17 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
1 messi 32 50
2 ronald 35 55
3 herry 40 51

mysql中需要先建表,否則會報錯。

CREATE TABLE sqooptest.hdfstomysql (
    id INT NOT NULL,
    name varchar(100) NOT NULL,
    age INT NOT NULL,
    score INT NOT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COLLATE=utf8_general_ci;

sqoop命令執行導出。

[hadoop@node01 ~]$ sqoop import \
> --connect jdbc:mysql://node01:3306/sqooptest \
> --username root \
> --password 123456 \
> --table hdfstomysql \  # 提前建立好的表
> --export-dir /hdfstomysql.txt \ # hdfs中目錄文件
> --input-fields-terminated-by " " # 指定文件數據的分隔符

導出后,發現mysql數據表中有了數據,ok。

以上,就是sqoop的使用入門,記錄一下以后使用。 

參考博文:

(1)https://blogs.apache.org/sqoop/entry/apache_sqoop_highlights_of_sqoop#comment-1561314193000 

(2)https://www.cnblogs.com/youngchaolin/p/12179320.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM