最近在項目中有用到使用sqoop將結構化數據上傳到hadoop的hdfs文件系統上,然後通過oozie進行定時調度,期中碰見了一些坑,將其記錄下來。在sqoop將數據導入進hdfs上,首先我們需要做的是將源數據庫的jdbc驅動添加進oozie的sqoop的lib目錄下,因爲sqoop導入數據,實質上是通過與數據庫建立一個jdbc連接,然後再進行 數據的導入的。一般oozie的lib庫在安裝時,會默認上傳到hdfs文件系統上的,而且放置的問題爲hdfs的根目錄下 /user/oozie/share/lib
如果你在hdfs文件系統上沒有找到lib庫,那麼你就需要自己上傳了。首先你需要找到oozie的安裝目錄。
找到oozie-sharelib.tar.gz文件,將其解壓出來,並且上傳到hdfs文件系統上。
tar -zvxf oozie-sharelib.tar.gz
解壓後,你可以把jdbc的驅動包放進sqoo的目錄下面再上傳到
最後在把這些包上傳到hdfs上
hadoop fs -put -f 本地資源路徑 hdfs存放資源路徑
接下就是oozie對sqoop的調度了,oozie是一個很強大的調度工具,因爲它有對shell操作的action,那麼就決定了它可以實現很多操作,同時它也有sqoop的action,我們可以直接使用sqoop的action來完成我們需要的調度任務
一個基本的定時調度,它應該包括三個文件,一個放置配置變量文件 job.properties,一個用來定時調度的調度文件 coordinator.xml,一個用來具體抽取數據的工作流文件 workflow.xml,
job.properties
nameNode=hdfs://master11:8020 #nomenode的地址和端口
jobTracker=master11:8050 #MapReduce的地址
queueName=oozie #該調度由哪個資源隊列來完成
examplesRoot=jobwork/all/ #設置一個路徑變量
oozie.libpath=/user/oozie/share/lib #ooize調度jar包資源路徑
oozie.use.system.libpath=true #是否使用oozie自帶的jar資源
oozie.coord.application.path=${nameNode}/${examplesRoot}/ext_All_coordinator.xml #定時調度的文件路徑
ext_bcdf_stationCar_workflow=${nameNode}/${examplesRoot}/ext_All_workflow.xml #工作流路徑
start=2018-12-12T16:10+0800 #設置一個開始調度時間
end=2098-08-20T00:00+0800 #設置一個結束
coordinate.xml
<coordinator-app name="cron-coord" frequency="${coord:minutes(15)}" start="${start}" end="${end}" timezone="GMT+0800"
xmlns="uri:oozie:coordinator:0.2">
<!--
frequency 設置調度的時間頻率,我這裏表示15分鐘調度一次
start 設置調度開始時間
end 設置調度結束時間
timezone 設置時區
-->
<action>
<workflow>
<app-path>${ext_bcdf_stationCar_workflow}</app-path>
<configuration>
<property>
<name>jobTracker</name>
<value>${jobTracker}</value>
</property>
<property>
<name>nameNode</name>
<value>${nameNode}</value>
</property>
<property>
<name>queueName</name>
<value>${queueName}</value>
</property>
<property>
<name>last_time</name>
<value>${coord:formatTime(coord:dateOffset(coord:nominalTime(), -15, 'MINUTE'), 'yyyy-MM-dd HH:mm:ss')}</value><!--獲取一個腳本當前執行前15分鐘的時間,並格式化我想要的格式-->
</property>
<property>
<name>current_time</name>
<value>${coord:formatTime(coord:dateOffset(coord:nominalTime(), 0, 'MINUTE'), 'yyyy-MM-dd HH:mm:ss')}</value> <!--獲取一個腳本當前執行時間,並格式化我想要的格式-->
</property>
</configuration>
</workflow>
</action>
</coordinator-app>
workflow.xml
<workflow-app xmlns="uri:oozie:workflow:0.4" name="ext_allinsert2">
<start to="extract_stationcar"/>
<action name="extract_stationcar">
<sqoop xmlns="uri:oozie:sqoop-action:0.2">
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<arg>import</arg>
<arg>--connect</arg>
<arg>jdbc:oracle:thin:@//*:1521/dzsw </arg>
<arg>--query</arg>
<arg>SELECT *FROM STATIONCAR where $CONDITIONS </arg>
<arg>--username</arg>
<arg>xc</arg>
<arg>--password</arg>
<arg>xc123 </arg>
<arg>--target-dir</arg>
<arg>/data/integration/ext_stationcar</arg>
<arg>-m</arg>
<arg>1</arg>
<arg>--fields-terminated-by </arg>
<arg>\\</arg>
<arg>--delete-target-dir</arg>
</sqoop>
<ok to="end" />
<error to="fail" />
</action>
<kill name="fail">
<message>[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>
以上三個文件就能完成每十五分鐘從數據庫裏面抽取數據到hdfs文件系統上面了。
使用需要注意的地方
1.action之間不能間接或者直接指向同一個action,比如action1執行成功指向action2,aciton1執行失敗指向aciton3,然後action2執行成功後指向action3,這樣是不被允許的,只有end和fail是可以被重複指向的,其餘所有類型的action都不能這麼使用,不然會類似下面這種錯誤
2.Ozoie在調度時,遇見腳本被kill,然後查看日誌,發現下面這個問題
No lease on /user/hadoop/oozie-oozi/0000092-181218090347177-oozie-oozi-W/extract_stationcar--sqoop/0000092-181218090347177-oozie-oozi-W@extract_stationcar@0 (inode 1058886)
這個問題咋一看可能會會認爲就是因爲找不到這個文件而引起的,但是後面又想想我這是單線程跑的,不可能出現別的線程將該文件刪除的情況,而且這個腳本之前還能跑的很好,最重要的是這個報錯信息一下是摸不着頭腦的,最後只能接着往下找,最終讓我找到了
The Network Adapter could not establish the connection
很明顯這個纔是腳本被kill掉的最終原因,從而引發了上面那個問題。