Sqoop 使用詳解(內含對官方文檔的解析)

Sqoop 是 Cloudera 公司創造的一個數據同步工具,如今已經徹底開源了。 html

目前已是 hadoop 生態環境中數據遷移的首選,另外還有 ali 開發的 DataX 屬於同類型工具,因爲社區的普遍使用和文檔的健全,調研以後決定使用 Sqoop 來作咱們以後數據同步的工具。java

咱們首先來看下 Sqoop 的工做流mysql

 

 他將咱們傳統的關係型數據庫 | 文件型數據庫 | 企業數據倉庫 同步到咱們的 hadoop 生態集羣中。sql

同時也能夠將 hadoop 生態集羣中的數據導回到傳統的關係型數據庫 | 文件型數據庫 | 企業數據倉庫中。shell

那麼 Sqoop 如何抽取數據呢數據庫

1. 首先 Sqoop 去 rdbms 抽取元數據。segmentfault

2. 當拿到元數據以後將任務切成多個任務分給多個 map。api

3. 而後再由每一個 map 將本身的任務完成以後輸出到文件。緩存

 

Sqoop import Command:服務器

先從最簡單的任務開始

sqoop import\
  --connect jdbc:mysql://10.66.38.125:3306/user_db \
--username cloudera \
--password secretkey \
--table department \
--target-dir /sqoopdata/departments \      # HDFS 的目標存儲位置
--where "department_id = 1000" \         # 指定條件,只有達成這個條件的纔會被 import 進來
-- m 1

就這個語句就能夠將咱們關係型數據庫中的某個表 import 進 HDFS 的某個位置。

 

一樣咱們能夠 import 某些字段進來生成文件

sqoop import \
  --connect jdbc:mysql://localhost:3306/retry_db \
  --username cloudera \ 
  --password secret \ 
  --table departments \
  --columns "dept_id, name" \  # 指定須要的字段
  --as-avrodatafile        # 指定存成 avro 數據文件

 

若是咱們要 import 一個庫裏面的全部表可使用

sqoop import-all-tables \
  --connect jdbc:mysql://localhost:3306/retry_db \
  --username cloudera \
  --password secret \
  --warehouse-dir /mydata    # HDFS parent for table 這個會將全部這些表都放到 HDFS 這個文件夾下面

 

Sqoop import Command:

咱們將數據從 Hadooop HDFS 導出向 RDBMS

sqoop export \
  --connect jdbc:mysql://localhost:3306/retry_db \
  --username cloudera \
  --password departments \
  --export-dir /sqoopdata/departments \    # HDFS source path for the export
  --table departments

 

Sqoop Job:

Sqoop 提供一種能力,能夠把咱們常常會執行的任務存儲成 jobs. 這些 jobs 能夠在將來任何一個時間點被咱們拿來使用。

sqoop job \
  --create job_name \
  --import \
  --connect jdbc:mysql://localhost:3306/retry_db \
  --username cloudera \
  --password departments 

 

經常使用姿式上面就介紹完了,當咱們須要將 MySQL 數據同步到 Hive 去的時候若是表尚未建立咱們只須要執行:

sudo-u hive sqoop import \
--connect jdbc:mysql://10.66.38.15:3306/user \      # 鏈接須要被同步的 MySQL
--username xxx \
--password xxx \
--table user \                         # 須要被同步的表
--delete-target-dir \                     # 以前有同步的文件已經存在刪除掉- m 1 \                             # 開一個 map 這個值得注意,不是每一個 source 表均可以輕鬆被分爲多個 map 的。若是你這裏要填寫非 1 的數最好去熟悉一些細節
--hive-import \                         
--hive-tableuser.user \
--create-hive-table \                     # 建立 hive 表
--hive-drop-import-delims                  # Drops \n, \r, and \01 from string fields when importing to Hive.

 

若是是表已經建立好而須要全量同步數據執行:

sudo -u hive sqoop import\
--connect jdbc:mysql://10.66.38.125:16033/user \
--username xxx \
--password xxx \
--table user \
--delete-target-dir \
--hive-overwrite \          # 全量重寫數據
- m 1 \
--hive-import \
--hive-table user.user \
--hive-drop-import-delims

 

一樣的 Sqoop 還支持 Hive 的增量同步。可是基於 mapreduce 的全量同步速度也快得超出想象。實測在三機集羣上(12核 | 32內存)機器上1分鐘基本能完成對 20 個字段左右的表 250w 條記錄的抽取。而且對目標數據庫機器的壓力不算大。是很是理想的大數據同步工具。

 

Sqoop 的配置參數很是之多,在使用的時候建議先擼一遍文檔(文檔不長大概擼一次 2 3 個小時左右),找到本身須要注意的地方和更多適合本身的功能在使用的時候就能避免踩坑。好比上面使用的   hive-drop-import-delims 參數的使用就是還沒看完文檔就使用形成的坑。咱們數據庫中有字段沒有過濾 \n 。有個用戶的名字被誤操做使用 \n 開頭致使 hive 誤覺得遇到了換行符,該數據不只錯亂並且後面字段所有被置爲 NULL。要避免這種問題一方面要對這個使用鏈上各個組件有所瞭解,更是應該讀一讀文檔能夠最大程度的避免踩坑。

----------------------------------------------------------分割線----------------------------------------------------------

下面將紀錄一下我全量閱讀 Sqoop 文檔以爲須要紀錄的一些東西。

 

7.2. 語法(Syntax)

首先咱們上面看到命令 Sqoop Command 這個 Command 實際上是指定 Sqoop 使用哪一種 Tool 。

$ sqoop help
usage: sqoop COMMAND [ARGS]

Available commands:
  codegen            Generate code to interact with database records
  create-hive-table  Import a table definition into Hive
  eval               Evaluate a SQL statement and display the results
  export             Export an HDFS directory to a database table
  help               List available commands
  import             Import a table from a database to HDFS
  import-all-tables  Import tables from a database to HDFS
  import-mainframe   Import mainframe datasets to HDFS
  list-databases     List available databases on a server
  list-tables        List available tables in a database
  version            Display version information

See 'sqoop help COMMAND' for information on a specific command.

能夠看到我上面舉例的全部內容都只是簡單的使用到了 export 和 import 還有 import-all-tables  工具。 還有很是多的工具沒有使用到。

由於 sqoop 是依賴 hadoop 生態的關係,因此也有響應的查找鏈,由於使用了 CDH 大禮包,因此我只是簡單的安裝了一下,相關的依賴都已經被配置好了包括 path

lrwxrwxrwx 1 root root 23 Nov 13 20:55 /usr/bin/sqoop -> /etc/alternatives/sqoop

 

7.2.1 鏈接數據庫服務器(Connecting to a Database Server)

下面咱們在使用 import tool 的時候遵循這個原則:

sqoop import (generic-args) (import-args)
sqoop-import (generic-args) (import-args)
While the Hadoop generic arguments must precede any import arguments, you can type the import arguments in any order with respect to one another.

當咱們在寫語句的時候應該首先使用了 generic-args 參數能夠是如下的參數。

Argument Description
--connect <jdbc-uri> Specify JDBC connect string
--connection-manager <class-name> Specify connection manager class to use
--driver <class-name> Manually specify JDBC driver class to use
--hadoop-mapred-home <dir> Override $HADOOP_MAPRED_HOME
--help Print usage instructions
--password-file Set path for a file containing the authentication password
-P Read password from console
--password <password> Set authentication password
--username <username> Set authentication username
--verbose Print more information while working
--connection-param-file <filename> Optional properties file that provides connection parameters
--relaxed-isolation Set connection transaction isolation to read uncommitted for the mappers.

後面的 import args 可選項就很是豐富。

好比能夠導入校驗使用的 class 刪除控制參數啥的。

Argument Description
--validate Enable validation of data copied, supports single table copy only.
--validator <class-name> Specify validator class to use.
--validation-threshold <class-name> Specify validation threshold class to use.
--validation-failurehandler <class-name> Specify validation failure handler class to use.

 

Argument Description
--append Append data to an existing dataset in HDFS
--as-avrodatafile Imports data to Avro Data Files
--as-sequencefile Imports data to SequenceFiles
--as-textfile Imports data as plain text (default)
--as-parquetfile Imports data to Parquet Files
--boundary-query <statement> Boundary query to use for creating splits
--columns <col,col,col…> Columns to import from table
--delete-target-dir Delete the import target directory if it exists
--direct Use direct connector if exists for the database
--fetch-size <n> Number of entries to read from database at once.
--inline-lob-limit <n> Set the maximum size for an inline LOB
-m,--num-mappers <n> Use n map tasks to import in parallel
-e,--query <statement> Import the results of statement.
--split-by <column-name> Column of the table used to split work units. Cannot be used with --autoreset-to-one-mapper option.
--split-limit <n> Upper Limit for each split size. This only applies to Integer and Date columns. For date or timestamp fields it is calculated in seconds.
--autoreset-to-one-mapper Import should use one mapper if a table has no primary key and no split-by column is provided. Cannot be used with --split-by <col> option.
--table <table-name> Table to read
--target-dir <dir> HDFS destination dir
--temporary-rootdir <dir> HDFS directory for temporary files created during import (overrides default "_sqoop")
--warehouse-dir <dir> HDFS parent for table destination
--where <where clause> WHERE clause to use during import
-z,--compress Enable compression
--compression-codec <c> Use Hadoop codec (default gzip)
--null-string <null-string> The string to be written for a null value for string columns
--null-non-string <null-string> The string to be written for a null value for non-string columns

 

7.2.3 自由的表查詢導入(Free-form Query Imports)

包括支持 free-form query .使用 --query 參數而後寫一個 sql 來過濾本身想要 import 的數據 just like 

$ sqoop import \
  --query 'SELECT a.*, b.* FROM a JOIN b on (a.id == b.id) WHERE $CONDITIONS' \
  --split-by a.id --target-dir /user/foo/joinresults

這個使用方法必需要使用 --target-dir 

 

7.2.4 掌控並行處理(Controlling Parallelism)

若是須要控制並行操做廣泛使用的是 -m 參數,--num-mapers參數。咱們能夠顯示的指定使用的用來並行分配的鍵,使用例如 --split-by employee_id 達到目標。

若是說咱們沒有使用 --split-by 參數主鍵也不是 int 型,可能會致使指定 -m 大於 1 的時候出問題。由於程序沒有辦法知道應該根據哪一個鍵來分配 map 任務。

另外咱們可使用 --autoreset-to-one-mapper 選項 --autoreset-to-one-mapper Import should use one mapper if a table has no primary key and no split-by column is provided. Cannot be used with --split-by <col> option.

 

7.2.5 掌控分佈式緩存(Controlling Distributed Cache)

使用 Oozie 調起 Sqoop job 執行任務的時候要注意一個 Controlling Distributed Cache 的問題。在第一個Sqoop做業期間,Oozie只會在每一個工做節點上對Sqoop依賴項進行一次本地化,並會在工做節點上重用jar來執行子節點做業。在Oozie啓動Sqoop命令時使用option - skip-dist-cache,能夠跳過Sqoop將依賴項複製到做業緩存並保存大量I/O的步驟。達到優化的目的。

 

7.2.6 掌控導入過程(Controlling the Import Process)

在控制導入的過程當中也有不少優化的地方能夠作,例如咱們在對關係行數據庫 MySQL 進行導入的時候,能夠經過使用關鍵字 --direct 加速導入的速度。他的原理是默認狀況下咱們會使用 JDBC 對數據庫進行鏈接,可是有一些數據庫提供了更高性能能夠指定數據庫進行轉移的工具。好比 MySQL 提供的 MySQL 提供的工具 mysqldump 使用 --direct 參數就能夠嘗試讓 Sqoop 使用這種方式去導出數據,可能會獲得更高的效能。當咱們在使用 --direct option 的時候還能夠傳遞一些潛在的參數給這個命令相似於這樣 將命令跟在 -- 後面

$ sqoop import --connect jdbc:mysql://server.foo.com/db --table bar \
    --direct -- --default-character-set=latin1

就能夠將後面的 --default-character-set=latin1 傳遞給 mysqldump 。

在 import 表的時候有兩個指定路徑的參數是衝突的  --warehouse-dir 和 --target-dir 都用於指定將生成的表放到指定的這個目錄下面。他們倆是衝突的,指定其中一個 option 便可。

在默認狀況下 import 這個工具都會將表導到一個新的路徑下面。若是路徑下面已經有相同名字的文件存在了,將會被拒絕導入。

若是使用 --append 參數 Sqoop將會將文件導入到臨時的文件目錄,而後重命名該文件成不與目標文件夾裏面名字衝突的名字。

 

7.2.7 掌控事務隔離級別(Controlling transaction isolation)

Sqoop 提供讀取數據庫 read-uncommitted 事務的能力,只須要帶上參數 --relaxed-isolation 便可。這個操做真是很是騷啊,通常應該不會用到並且也不是全部數據庫都支持,好比官方文檔說 ORACLE 就是不支持的。

 

7.2.8 掌控 mapping 時候的字段類型(Controlling type mapping

能夠對指定同步的表進行 schema 的映射轉換,而且能夠指定經過 java 或者 hive 類型的轉換。例如:

Argument    Description
--map-column-java <mapping>    Override mapping from SQL to Java type for configured columns.
--map-column-hive <mapping>    Override mapping from SQL to Hive type for configured columns.

Sqoop is expecting comma separated list of mapping in form <name of column>=<new type>. For example:

$ sqoop import ... --map-column-java id=String,value=Integer

另外須要注意的是  --map-column-hive 使用該參數須要使用 urlencode 對轉換 key value 進行轉換。例如

use DECIMAL(1%2C%201) instead of DECIMAL(1, 1)

若是轉換不正確,Sqoop 會 raise exception

 

7.2.10 增量更新(Incremental Imports

關於使用 Sqoop 進行增量更新處理, Sqoop 提供了三個字段來處理增量更新相關的內容

Argument Description
--check-column (col) Specifies the column to be examined when determining which rows to import. (the column should not be of type CHAR/NCHAR/VARCHAR/VARNCHAR/ LONGVARCHAR/LONGNVARCHAR)
--incremental (mode) Specifies how Sqoop determines which rows are new. Legal values for mode include append and lastmodified.
--last-value (value) Specifies the maximum value of the check column from the previous import.

Sqoop 自己支持兩種不一樣的方式進行增量更新,分別是 append 和 lastmodified 咱們使用 --incremental 參數去指定要使用的增量更新類型。

增量更新的文章有不少基本上創建在兩個基礎上。(以前的數據若是被 update 沒有辦法經過這兩種增量更新機制被更新)

1. 能夠提供相似於自增 id 這樣的字段,而且小於這個點的字段能夠從上次這個點位繼續日後增長。使用 --last-value 須要注意的是可使用 Sqoop job 在第一次指定了開始的 last-value 值以後 Sqoop 會保存下來此次執行完以後 last-value 值的節點,下次執行的時候會基於這個繼續執行。

2. 能夠提供一個最後修改的字段,例如 update_time 這樣的字段,全部大於這個 update_time 時間的字段將在下個節點被增量追加到後面。--check-column update_time

 

7.2.11 文檔格式化(File Formats)

咱們一般導入兩種格式的文件形式,一種是 textfile 也是默認類型。還有一種是 SequenceFiles

咱們能夠經過指定 --as-textfile 參數顯示指定使用 textfile 導入。textfile 又稱 delimited text 在非二進制數據狀況下很是通用,並且很容易支持相似於像 Hive 這種數據庫表的生成。

SequenceFiels 是一種二進制格式用於往自定義的記錄指定的 data types 中存儲獨立的記錄。這些 data types 表現爲 java 的類。

另外咱們也可使用表協議 好比咱們可使用 Apache Avro。

默認狀況下 Sqoop 不會幫咱們壓縮文件使用 -z 或者 --compress 參數或者使用其餘壓縮參數好比 --compression-codec 對 SequenceFile text 或者 Avro 文件進行壓縮。

 

7.2.12. 大的對象的處理(Large Objects)

Sqoop 對 blob 和 clob  columns 都有特別的處理方式。他們儘可能不要像常規字段這樣所有 load 進內存進行操做。而是使用流式的方法來進行處理,而且和其餘數據進行內聯存儲。(這一塊我徹底沒有看懂是什麼意思,水平不夠能夠自行前往官方文檔查看。。。。。。)

 

Table 6. Output line formatting arguments:

Argument Description
--enclosed-by <char> Sets a required field enclosing character
--escaped-by <char> Sets the escape character
--fields-terminated-by <char> Sets the field separator character
--lines-terminated-by <char> Sets the end-of-line character
--mysql-delimiters Uses MySQL’s default delimiter set: fields: , lines: \n escaped-by: \ optionally-enclosed-by: '
--optionally-enclosed-by <char> Sets a field enclosing character

 默認狀況下 Sqoop 會使用逗號 comma(,) 來做爲字段之間的分隔符,使用換行符 \n 來區別每一條記錄。

Sqoop 官方文檔推薦咱們使用 unambiguous 也就是顯示清晰的去指定字段分隔符和行分隔符。好比直接使用 --mysql-delimiters

下面的敘述我想了好久想翻譯成中文我都以爲不是很直接 因此仍是直接貼文檔吧。

If unambiguous delimiters cannot be presented, then use enclosing and escaping characters. The combination of (optional) enclosing and escaping characters will allow unambiguous parsing of lines. For example, suppose one column of a dataset contained the following values:

Some string, with a comma.
Another "string with quotes"

The following arguments would provide delimiters which can be unambiguously parsed:

$ sqoop import --fields-terminated-by , --escaped-by \\ --enclosed-by '\"' ...

(Note that to prevent the shell from mangling the enclosing character, we have enclosed that argument itself in single-quotes.)

The result of the above arguments applied to the above dataset would be:

"Some string, with a comma.","1","2","3"...
"Another \"string with quotes\"","4","5","6"...

Here the imported strings are shown in the context of additional columns ("1","2","3", etc.) to demonstrate the full effect of enclosing and escaping. The enclosing character is only strictly necessary when delimiter characters appear in the imported text. The enclosing character can therefore be specified as optional:

$ sqoop import --optionally-enclosed-by '\"' (the rest as above)...

Which would result in the following import:

"Some string, with a comma.",1,2,3...
"Another \"string with quotes\"",4,5,6...
[Note] Note

Even though Hive supports escaping characters, it does not handle escaping of new-line character. Also, it does not support the notion of enclosing characters that may include field delimiters in the enclosed string. It is therefore recommended that you choose unambiguous field and record-terminating delimiters without the help of escaping and enclosing characters when working with Hive; this is due to limitations of Hive’s input parsing abilities.

The --mysql-delimiters argument is a shorthand argument which uses the default delimiters for the mysqldump program. If you use the mysqldump delimiters in conjunction with a direct-mode import (with --direct), very fast imports can be achieved.

While the choice of delimiters is most important for a text-mode import, it is still relevant if you import to SequenceFiles with --as-sequencefile. The generated class' toString() method will use the delimiters you specify, so subsequent formatting of the output data will rely on the delimiters you choose.

 

Table 8. Hive arguments:

Argument Description
--hive-home <dir> Override $HIVE_HOME
--hive-import Import tables into Hive (Uses Hive’s default delimiters if none are set.)
--hive-overwrite Overwrite existing data in the Hive table.
--create-hive-table If set, then the job will fail if the target hive
  table exists. By default this property is false.
--hive-table <table-name> Sets the table name to use when importing to Hive.
--hive-drop-import-delims Drops \n\r, and \01 from string fields when importing to Hive.
--hive-delims-replacement Replace \n\r, and \01 from string fields with user defined string when importing to Hive.
--hive-partition-key Name of a hive field to partition are sharded on
--hive-partition-value <v> String-value that serves as partition key for this imported into hive in this job.
--map-column-hive <map> Override default mapping from SQL type to Hive type for configured columns. If specify commas in this argument, use URL encoded keys and values, for example, use DECIMAL(1%2C%201) instead of DECIMAL(1, 1).

咱們想要使用 Sqoop 抽取 RDBMS 的數據到 Hive 多是再常見不過的情形了,因此這一部分很重要也多是咱們最常使用的部分。

 

7.2.13 導入數據到 Hive (Importing Data Into Hive)

Sqoop 抽取 RDBMS 的數據到 Hive 會先將數據抽取出來在 HDFS 上的指定路徑上放一下。若是指定路徑上已經有文件,可是 Hive 裏面卻沒有你的表你還須要指定 --delete-target-dir 來刪除 HDFS 的文件,而後從新上傳一份。當上傳到 HDFS 結束以後,會使用 Hive 的命令 LOAD DATA INPATH 將文件移動到 Hive 的 warehouse 目錄下面若是指定了 Hive 表的建立表參數會直接建立 Hive 表而且映射上數據。

若是表已經存在了 可使用 --hive-overwrite 將數據直接覆蓋。雖然Hive支持轉義字符,但它不處理換行字符。此外,它不支持在封閉字符串中包含字段分隔符的封閉字符的概念。所以,在使用Hive時,建議您選擇明確的字段和記錄終止分隔符,而無需轉義和包圍字符;這是因爲Hive的輸入解析能力的限制。若是您在將數據導入到Hive時使用了--escapby,--enclosed-by, or -optionally-enclosed-by, Sqoop將打印一條警告消息。

Hive 默認會使用 \n 分割行,使用\01 分割字段。若是說咱們的數據裏面有這些字段就可能會有衝突,咱們須要使用 --hive-drop-import-delims 把這些都替換掉。上面表能夠參照這個 option 的意義。另外也可使用 --hive-delims-replacement 將衝突的字段給替換掉。

另外還有一個值得注意的地方 Hive 表默認將從 RDBMS 裏面抽取出來的 NULL value 數據轉換成 null string 。這個在使用的時候就會出現問題,由於以前是一個空,如今卻變成了一個 null 字符串。因此咱們須要處理一下, Hive在本身的體系裏面使用 \N 來表示 NULL 咱們使用 --null-string 和 --null-non-string 參數處理 import job 使用 --input-null-string 和 --input-null-non-string  處理 export job 。舉個🌰

$ sqoop import  ... --null-string '\\N' --null-non-string '\\N'

另外咱們可使用 --hive-partition-key 和 --hive-partition-value 參數來指定分區鍵提高 hive 的處理能力。

這一塊 sqoop 只支持單分區導入。

這一塊更詳細的能夠參考一下 hive 文檔。

27.2.5. MySQL: Import of TINYINT(1) from MySQL behaves strangely

Problem: Sqoop is treating TINYINT(1) columns as booleans, which is for example causing issues with HIVE import. This is because by default the MySQL JDBC connector maps the TINYINT(1) to java.sql.Types.BIT, which Sqoop by default maps to Boolean.

Solution: A more clean solution is to force MySQL JDBC Connector to stop converting TINYINT(1) to java.sql.Types.BIT by adding tinyInt1isBit=false into your JDBC path (to create something like jdbc:mysql://localhost/test?tinyInt1isBit=false). Another solution would be to explicitly override the column mapping for the datatype TINYINT(1) column. For example, if the column name is foo, then pass the following option to Sqoop during import: --map-column-hive foo=tinyint. In the case of non-Hive imports to HDFS, use --map-column-java foo=integer.

 

不知不覺感受寫了不少。。。發現才把 import 工具寫完。其實 Sqoop 使用最多的場景也就是 import 工具的場景,其餘場景使用的頻率應該不高,我找時間再整理一篇文章來寫別的工具的功能hh 這篇就到這裏吧!

 

Reference:

https://archive.cloudera.com/cdh6/6.0.1/docs/sqoop-1.4.7-cdh6.0.1/SqoopUserGuide.html  Sqoop User Guide (v1.4.7-cdh6.0.1)

https://blog.csdn.net/Gavin_chun/article/details/78314065  SQOOP從MySQL導入數據到Hive

https://segmentfault.com/a/1190000002532293  sqoop  導入關係數據庫到 hive

https://blog.csdn.net/myrainblues/article/details/43673129  sqoop使用中文手冊

https://blog.csdn.net/lyp5257918/article/details/53820690  sqoop抽取文本數據到hive因爲存在空字符致使字段錯位和丟失錯誤

https://www.youtube.com/watch?v=72M5lMP8dMg  COSO IT Sqoop Tutorial 

https://blog.csdn.net/taisenki/article/details/78974121  Sqoop 數據導入多分區Hive解決方法

相關文章
相關標籤/搜索