1. 程式人生 > 實用技巧 >sqoop同步工具詳情

sqoop同步工具詳情

未經允許不得轉載

來源

資料同步工具(針對各種資料庫):

開源工具:

sqoop:

datax:

kettle:

cannal:

自定義程式碼:

閉源工具:

1、關係型資料庫中資料怎麼匯入到hdfs、hbase(壓縮或者非壓縮)?

2、hdfs中的資料(壓縮)怎麼匯入關係型資料庫中?

3、增量資料匯入?

2sqoop****定義

sqoop是一個hadoop和關係型資料庫之間高效批量資料同步工具。

匯入(import: 關係型資料庫 -----> hadoop(hdfs\hive\hbase)

匯出****(export):hadoop(hdfs) ----> 關係型資料庫

資料同步本質:

使用mapreudce來進行資料同步,主要是使用mapper。

優點:跨平臺資料同步

缺點:不是很靈活。

3****、sqoop的安裝

準備:

需要hadoop的安裝

需要jdk

需要準備關係型資料庫的依賴jar包

安裝

1、解壓配置環境變數即可

[root@hadoop01 local]# tar -zxvf /home/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C 

/usr/local/ 

[root@hadoop01 local]# mv ./sqoop-1.4.7.bin__hadoop-2.6.0/ ./sqoop-1.4.7 

2、配置環境變數

[root@hadoop01 local]# vi /etc/profile [root@hadoop01 local]# source /etc/profile 
驗證
[root@hadoop01 local]# which sqoop

常見命令:

3、配置sqoop-env.sh檔案

[root@hadoop01 local]# mv ./sqoop-1.4.7/conf/sqoop-env-template.sh ./sqoop- 1.4.7/conf/sqoop-env.sh 
[root@hadoop01 local]# vi ./sqoop-1.4.7/conf/sqoop-env.sh 
修改如下: 
#Set Hadoop-specific environment variables here. 

#Set path to where bin/hadoop is available 
export HADOOP_COMMON_HOME=/usr/local/hadoop-2.7.1/

#Set path to where hadoop-*-core.jar is available 
export HADOOP_MAPRED_HOME=/usr/local/hadoop-2.7.1/ 

#set the path to where bin/hbase is available 
export HBASE_HOME=/usr/local/hbase-1.1.2/ 

#Set the path to where bin/hive is available 
export HIVE_HOME=/usr/local/hive-2.3.6/

#Set the path for where zookeper config dir is
export ZOOCFGDIR=/usr/local/zookeeper-3.4.10/

4、測試

[root@hadoop01 local]# sqoop-version 
Warning: /usr/local/sqoop-1.4.7//../hcatalog does not exist! HCatalog jobs will fail. 

Please set $HCAT_HOME to the root of your HCatalog installation. 
Warning: /usr/local/sqoop-1.4.7//../accumulo does not exist! Accumulo imports will fail. 

Please set $ACCUMULO_HOME to the root of your Accumulo installation. 
Warning: /usr/local/sqoop-1.4.7//../zookeeper does not exist! Accumulo imports will fail. 

Please set $ZOOKEEPER_HOME to the root of your Zookeeper installation. 
19/12/02 10:13:30 INFO sqoop.Sqoop: Running Sqoop version: 1.4.7 Sqoop 1.4.7 

git commit id 2328971411f57f0cb683dfb79d19d4d19d185dd8 
Compiled by maugli on Thu Dec 21 15:59:58 STD 2017

4sqoop****的實戰

sqoop只允許將語句放到1行,如果想要放到多行,需要\來表示換行。

4.1 sqoop列出mysql****中的所有庫

格式: 
$ sqoop list-databases (generic-args) (list-databases-args) 
$ sqoop-list-databases (generic-args) (list-databases-args)
準備: 
引入mysql的驅動包。 
[root@hadoop01 sqoop-1.4.7]# cp /home/mysql-connector-java-5.1.6-bin.jar ./lib/
語句: 
sqoop list-databases --connect jdbc:mysql://hadoop01:3306 \ 
--username root \ 
--password root 

結果: 
information_schema 
azkaban 
bap_dm 
bap_ods 
hive 
kettle 
mysql 
performance_schema 
sales_report 
sales_source 
test 
ywp

4.2 sqoop列出mysql****某庫的所有表

sqoop list-tables --connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root

4.3 sqoop****資料的匯入

資料匯入import

資料匯出export

格式:

$ sqoop import (generic-args) (import-args) 
$ sqoop-import (generic-args) (import-args)

匯入某個表的所有資料到hdfs中:

sqoop import --connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table u1 \ 
--delete-target-dir \ 
--target-dir '/1906sqoop/u1' \ 
--split-by id

並行匯入:

sqoop import --connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table u1 \ 
--delete-target-dir \ 
--target-dir '/1906sqoop/u2' \ 
--split-by id \ -m 1

選擇列匯入:

法一: 
sqoop import --connect jdbc:mysql://hadoop01:3306/test \
--username root \ 
--password root \ 
--table stu \ 
--driver com.mysql.jdbc.Driver \ 
--columns 'id,name,age' \ 
--where id > 6 \ 
--delete-target-dir \ 
--target-dir '/1906sqoop/u3' \ 
--split-by id \ -m 1 

法二: sqoop import 
--connect jdbc:mysql://hadoop01:3306/test \ 
--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/u6' \ 
--split-by id \ -m 1 \ 
--fields-terminated-by '\t' \ 
--null-string '\\N' \ 
--null-non-string '0'

單引號和雙引號的區別:

--query 'select id,name,age from stu where id > 6 and $CONDITIONS' \ 
--query "select id,name,age from stu where id > 6 and \$CONDITIONS" \

引數屬性:

--table mysql中的表 
--delete-target-dir 如果hdfs中的目標目錄存在,則刪除 
--target-dir 匯入到hdfs中的那個目錄 
--split-by 切分工作單元,後面需要指定column 
-m 使用n個map task來並行匯入,一般和
--split-by搭配使用 
--columns 匯入指定列,和table搭配使用 
--where 指定條件
--driver 指定驅動引數 
--query 指定執行的sql語句,不能和--table搭配使用 
-warehouse-dir 倉庫目錄,專案可以指定一個根目錄 
--fields-terminated-by 匯入的欄位分隔符,預設是,分割 
--null-string 字串列空值處理 --null-non-string 非字串列空值處理 
--as-parquetfile 輸出的資料檔案格式 
--fetch-size 10000 一次獲取的資料條數 
--compress 指定壓縮 
--compression-codec 指定壓縮型別,預設gzip壓縮

指指定檔案格式匯入:

sqoop import 
--connect jdbc:mysql://hadoop01:3306/test \ 
--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/u5' \ 
--split-by id \ -m 1 \ 
--fields-terminated-by '\t' \ 
--null-string '\\N' \ 
--null-non-string '0' \ 
--as-parquetfile \ 
--fetch-size 10000

問題:

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 2、

匯入指定列錯誤 :java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@4c39bec8 is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries. 

解決方法: 
加上該屬性: --driver com.mysql.jdbc.Driver \

思考:

1、怎麼監控資料是否完全匯入??? 
2、某表如果2G資料,設定多少個mapper合適?

4.4 sqoop****資料的匯出

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語句

sqoop export --connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table u2 \ 
--driver com.mysql.jdbc.Driver \ 
--export-dir '/1906sqoop/u2/*' \ 
-m 1 

法二: 
先從新匯入資料: 
sqoop import --connect jdbc:mysql://hadoop01:3306/test \ 
--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'


匯出語句: 
sqoop export --connect jdbc:mysql://hadoop01:3306/test \ 
--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

注:

1、匯出資料中有些列值有"null",會報沒法解析

2、匯出資料的型別需要和mysql中的一致(能自動轉沒有問題)

5sqoop****高階例項

5.1 sqoop匯入到hive****表

方式:

1、直接匯入到hdfs中的某個目錄,然後再建立表去指向該目錄即可。

2、直接匯入到hive的表中。

準備:

1、需要hive能正常使用(metastore服務啟動起來) 

2、將hive的exec.jar包複製到sqoop的lib目錄下
sqoop import \ 
--connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table u2 \ 
--hive-import \ --hive-overwrite \ 
--hive-table u2 \ 
-m 1

分解步驟:

1、匯入hdfs中的目錄下

2、將該目錄下的資料裝載到hive表中

問題:

1、hive-1.2.1 和 sqoop-1.4.7 ,從mysql匯入資料到hive表中,hive中查詢不出來表,元資料也沒有。


解決辦法:

將hive-site.xml放到sqoop的conf目錄中即可。

5.2 sqoop****匯入到hive的分割槽表

方式:

1、sqoop匯入資料到hdfs目錄(分割槽的形式),然後再hive中建立分割槽表,最後使用alter table add

partition...

2、直接使用sqoop匯入都分割槽表中ss

sqoop import \ 
  --connect jdbc:mysql://hadoop01:3306/test \
  --username root \ --password root \
  --hive-import \
  --hive-overwrite \
  --hive-partition-key 'bdp_day' \
  --hive-partition-value '20191202' \
  --target-dir /root/u22 \
  --hive-table u22 \
  --num-mappers 1 \ 
  --query 'SELECT * FROM u2 where $CONDITIONS;'

5.3 hivejob

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:

sqoop job --list

建立一個sqoop的job:

sqoop job --create sq2
-- import --connect jdbc:mysql://hadoop01:3306/test \
--username root \
--password root \ 
--table u2 \ 
--driver com.mysql.jdbc.Driver \
--delete-target-dir \ 
--target-dir '/1906sqoop/u9' \ 
--split-by id \ 
-m 1

執行sqoop的job:

sqoop job --exec sq1 


執行的時候回讓輸入密碼: 
輸入該節點使用者的對應的密碼即可 
1、配置客戶端記住密碼(sqoop-site.xml)追加 
  <property> 
     <name>sqoop.metastore.client.record.password</name> 
     <value>true</value> 
  </property> 

2、將密碼配置到hdfs的某個檔案,我們指向該密碼檔案 
說明:在建立Job時,使用--password-file引數,而且非--passoword。主要原因是在執行Job時使用--password引數將有警告,並且需要輸入密碼才能執行Job。當我們採用--password-file引數時,執行 
Job無需輸入資料庫密碼。 
echo -n "root" > sqoop.pwd 
hdfs dfs -rm sqoop.pwd /input/sqoop.pwd 
hdfs dfs -put sqoop.pwd /input 
hdfs dfs -chmod 400 /input/sqoop.pwd 
hdfs dfs -ls /input 
-r-------- 1 hadoop supergroup 6 2018-01-15 18:38 /input/sqoop.pwd

檢視sqoop的job:

sqoop job --show sq1

刪除sqoop的job:

sqoop job --delete sq1

問題:

1、建立job報錯:19/12/02 23:29:17 ERROR sqoop.Sqoop: Got exception running Sqoop: 
java.lang.NullPointerException 
java.lang.NullPointerException 
         at 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目錄中。 

job的好處:

1、一次建立,後面不需要建立,可重複執行job即可

2、它可以幫我們記錄增量匯入資料的最後記錄值

3、job的元資料儲存目錄:$HOME/.sqoop/

5.4 更新並插入匯出

場景:

多維結果資料匯出;異常重跑資料

--update-mode : updateonly,是預設,僅更新;allowinsert:更新並允許插入 
--update-key :
CREATE TABLE `upv` ( 
  `country_id` int(11) NOT NULL AUTO_INCREMENT, 
  `visits` int(11) DEFAULT NULL, 
  PRIMARY KEY (`country_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

匯出語句: 
sqoop export --connect jdbc:mysql://hadoop01:3306/test \ 
--username root --password root --table upv \ 
--export-dir /1906sqoop/upv/* \ 
--input-fields-terminated-by "," \ 
--update-mode allowinsert \ 
--update-key country_id 

5.5 sqoop匯出parquet****格式的資料

匯入資料到HDFS中為parqut格式: 
sqoop import --connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--query 'select id,age from stu where id > 6 and $CONDITIONS' \
--driver com.mysql.jdbc.Driver \ 
--delete-target-dir \ 
--target-dir '/1906sqoop/u9' \ 
--split-by id \ 
-m 1 \ 
--fields-terminated-by '\t' \ 
--null-string '\\N' \ 
--null-non-string '0' \ 
--as-parquetfile 

匯出語句:

建立表: 

CREATE TABLE `par` ( 
  `id` int(11) NOT NULL DEFAULT '0', 
  `age` int(1) DEFAULT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

hive建立表: 
create table if not exists par( 
  `id` int, 
   `age` int 
)
row format delimited fields terminated by '\t' 
stored as parquet 
location '/1906sqoop/u9/' 

;

將hive包中的lib目錄下的hcatlog相關包拷貝到sqoop的lib目錄中去:

[root@hadoop01 sqoop-1.4.7]# cp /usr/local/hive-2.3.6/lib/hive-hcatalog-core-2.3.6.jar /usr/local/hive-2.3.6/lib/hive-hcatalog-server-extensions-2.3.6.jar  ./lib/ 

匯出parquet格式語句:

sqoop export \ 
--connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table par \ 
--hcatalog-database default \ 
--hcatalog-table par \ 
-m 1 

引數說明: 
--table:MySQL庫中的表名 
--hcatalog-database:Hive中的庫名 
--hcatalog-table:Hive庫中的表名,需要抽數的表

5.6 定期執行

方法:

1、直接排程框架排程sqoop語句

2、將sqoop語句封裝到shell指令碼中,排程框架排程指令碼或者直接在伺服器中使用crontab來定時

vi /home/add_u2.sh 
#!/bin/bash 

/usr/local/sqoop-1.4.7/bin/sqoop import \ 
--connect jdbc:mysql://hadoop01:3306/test \ 
--username root \ 
--password root \ 
--table u2 \ 
--hive-import \ 
--hive-overwrite \ 
--hive-table u2 \ 
-m 1 

授予可執行許可權: 
[root@hadoop01 sqoop-1.4.7]# chmod a+x /home/add_u2.sh 

定時:

[root@hadoop01 sqoop-1.4.7]# crontab -e 
\* 2 * * * /home/add_u2.sh >> /home/u2.log 

自己搗鼓

1、將資料中 sales_source.sql載入到自己mysql中,並且使用sqoop將裡面的三章表的資料匯入到hive 
表中,hive的表名和sales_source.sql中的表名一樣,hive的庫名統一叫sales_ods. 

需求: 
a、sales_order表需要增量匯入,必須是分割槽表 
b、其它兩張表全量匯入,不用分割槽表 
c、將其sqoop語句放到shell指令碼中,執行指令碼即可執行把3張表的資料匯入即可。

提示
------------
customer : 全量 
product : 全量 
orders : 增量 

vi /home/hw01.sh 
#!/bin/bash 
create database if not exists sales_ods; 
sqoop import \ 
--connect jdbc:mysql://hadoop01:3306/sales_source \ 
--username root \ 
--password root \ 
--table customer \
--hive-import \ 
--hive-overwrite \ 
--hive-table sales_ods.customer \ 
-m 1 

sqoop import \ 
--connect jdbc:mysql://hadoop01:3306/sales_source \ 
--username root \ 
--password root \ 
--table product \ 
--hive-import \ 
--hive-overwrite \ 
--hive-table sales_ods.product \ 
-m 1

思考:

1、怎麼監控資料是否完全匯入???

使用shell指令碼去查詢mysql中某表的資料,然後和hive中表的行數對比。

#!/bin/bash 
u2_cnt=`mysql -uroot -proot -e "select count(*) from test.u2"` 
echo "u2 table of test total rows:${u2_cnt}" 

2、某表如果2G資料,設定多少個mapper合適?

建議128M(和塊大小一致)一個mapper即可。