1. 程式人生 > >其實我不會程式設計,只會臉滾鍵盤

其實我不會程式設計,只會臉滾鍵盤

背景

之前的工作中使用Hive一直都是用的內表,對於外表一直都沒有正經研究過,最近偶爾使用了一次,就整出了不小的麻煩,而且發現是跟HDFS許可權有關,然而就發現關於HDFS的許可權問題理解的還是太少了,所以把問題整理一下。

一,Hive外表載入HDFS檔案錯誤

場景是這樣的:首先在Hive中新建一張外表
DROP TABLE IF EXISTS quickstart;
CREATE EXTERNAL TABLE quickstart (a INT, b STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '|';

然後試圖用load語句把資料載入到這張表:

LOAD DATA LOCAL INPATH '/root/quickstart.txt' OVERWRITE INTO TABLE quickstart;

此時當然是會報錯的啦,因為這裡的local指的是 hive server所在機器的lcoal,訪問方式應該類似於/LOCALWORKSPACE/manual-ut/manual_data/manual_crud_tmp/quickstart.txt這種格式才對。 因為感覺寫法比較麻煩,於是決定還是上傳到HDFS上好了:

hadoop fs -put /root/quickstart.txt /tmp/quickstart.txt

然後再執行load命令:

LOAD DATA INPATH '/tmp/quickstart.txt' OVERWRITE INTO TABLE quickstart;

上面這條語句給出的錯誤是:

0: jdbc:hive2://localhost:10000/default> LOAD DATA INPATH '/tmp/quickstart.txt' OVERWRITE INTO TABLE quickstart;
	Error: EXECUTION FAILED: Task MOVE error HiveException: [Error 20531] Unable to move source hdfs://nameservice1/tmp/quickstart.txt to destination hdfs://nameservice1/inceptor1/user/hive/warehouse/xh.db/hive/quickstart/quickstart.txt (state=08S01,**code=20531**)

根據文件,Hive中的錯誤程式碼code=20531的原因可能有(但不僅限於)

1.IOException,即檔案讀取失敗。 2. dst目錄建立失敗。 3. 刪除src檔案失敗。當執行INSERT OVERWRITE DIRECTORY命令將查詢結果儲存到檔案時,src檔案是臨 時檔案,需要刪除。若刪除失敗將報20531錯誤。

首先排除第一個原因,因為在此之前我有修改過原始檔的許可權:

hadoop fs -chmod 777 /tmp/quickstart.txt

然後是第二個原因也不可能,因為目的資料夾/user/hive/warehouse/xh.db/hive/quickstart下,這個目錄的所有者是:hive:hive:drwxr-xr-x,目錄的所有者hive也就是我登陸hive時候的使用者名稱,可能也不存在許可權不足的問題。

那麼原因就應該是第三個了,此時牽扯到了HDFS的許可權問題

二,HDFS使用者許可權

關於HDFS的使用者許可權問題,一直都沒有怎麼關注過,直到這個問題出現之後才意識到這一點還是很重要的。

HDFS本身並沒有提供使用者名稱、組等的建立和管理,在客戶端操作Hadoop時,Hadoop自動識別執行命令所在的程序的使用者名稱和使用者組,然後檢查是否具有許可權。 本例子中,我用的root使用者登陸的hive所在的那臺Linux伺服器(因為是測試環境,所以可以 簡單粗暴點),在HDFS上建立了檔案/tmp/quickstart.txt之後,它的所有者預設是root(HDFS根據上面的規則新建的使用者) 而我在HIVE中新建外表的時候,就會在HDFS的指定目錄上新建一個目錄(本例中是/user/hive/warehouse/xh.db/hive/quickstart),這個目錄的所有者預設是hive(同樣是根據上面的規則新建的使用者) 在執行LOAD指令時候,HDFS底層是會把原始檔mv到目的表所在的目錄下的,也就是需要刪除src檔案,在本例中,HDFS中發生事情是要使用hive使用者刪除root使用者的檔案/tmp/quickstart.txt。 那麼問題來了:src檔案/tmp/quickstart.txt許可權已經是777了,為何還是會報告許可權不足的錯誤呢?

三,sticky bit:粘滯位

為了徹底搞懂這個問題,我做了另外的驗證試驗 首先,在hdfs新建一個目錄,許可權777,所有者是hive使用者
drwxrwxrwx   - hive  hadoop          0 2018-08-04 03:09 /tmp/emp_id_hdfs.txt

然後用root使用者登陸了HDFS叢集所在節點的Linux ,在沒有開通任何認證的情況下,執行命令

hadoop fs -rm  -r  /tmp/emp_id_hdfs.txt

此時會報錯:

[[email protected] tmp]# hadoop fs -rm  -r  /tmp/emp_id_hdfs.txt
2018-08-04 03:12:55,164 INFO util.KerberosUtil: Using principal pattern: HTTP/_HOST
2018-08-04 03:12:56,262 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 1440 minutes, Emptier interval = 0 minutes.
rm: Failed to move to trash: hdfs://nameservice1/tmp/emp_id_hdfs.txt: **Permission denied by sticky bit: user=root, path="/tmp/emp_id_hdfs.txt":hive:hadoop:drwxrwxrwx,** parent="/tmp":hdfs:hadoop:drwxrwxrwt

出現了新的問題:Permission denied by sticky bit 並且告訴我詳細資訊:root沒有足夠的許可權刪除目錄/tmp/emp_id_hdfs.txt

[[email protected] tmp]# hadoop fs -ls -d /tmp
drwxrwxrwt   - hdfs hadoop          0 2018-08-04 00:27 /tmp

有sticky bit,所以/tmp/emp_id_hdfs.txt這個目錄只有它的所有者hive可以刪除,所以會報本節的錯:Permission denied by sticky bit

總結

總結一下,用root使用者在HDFS的/tmp目錄下建立的資料檔案,當在Hive中執行load指令的時候,HDFS會默然建立一個hive使用者來把/tmp目錄下的資料檔案mv到Hive表所在的目錄下,也就相當於要刪除掉/tmp目錄下的資料檔案,因為/tmp目錄設定了sticky bit,會導致HDFS的hive使用者mv資料檔案失敗(本例中只有檔案所有者root才可以刪除它),所以Hive會報錯:code=20531,也就是刪除src檔案失敗。