文章目錄
- 0. 前情提要
- 1. 解決方案
- 2. 系統環境
- 3. 問題描述
- 4. 問題分析
- 5. 解決思路
- 6. 仍存在的問題
- 參考資料
0. 前情提要
在服務器上用standalone模式部署了Spark,使用本地檔案系統(沒有使用HDFS),在多用戶提交Spark application計算任務并保存結果到本地檔案系統時出現問題,保存時提示:
java.io.IOException: mkdirs failed to create file
或
java.io.IOException: Failed to rename DeprecatedRawLocalFileStatus
因為很少有像我這么“奇葩”的使用場景(單機Standalone+本地檔案系統+多用戶),所以花了兩三個小時搜索研究才最終解決,
1. 解決方案
不想看完整問題分析的同學可以直接采用下面的解決方案:
- 關閉Spark
- 使
root用戶執行start-master.sh和start-worker.sh啟動Spark - 在創建
SparkSession時,將spark.hadoop.fs.permissions.umask-mode設定為000,可以在Spark安裝目錄的conf/spark-defaults.conf檔案內設定;以pySpark為例,也可以通過這種方式在運行時設定:
spark = SparkSession \
.builder \
.master("spark://youraddress:7077") \
.config("spark.hadoop.fs.permissions.umask-mode", "000") \
.appName("yourname") \
.getOrCreate()
- 如果你不存在多用戶使用的場景,可以忽略第2、3步,使用相同的用戶啟動Spark和提交Spark任務即可
感興趣的同學可以接著往下看前因后果,不感興趣的可以右上角了
2. 系統環境
- 單臺服務器:68 vCPUs + 600GB RAM
- CentOS 8
- Spark 3.1.2 (Standalone模式,使用本地檔案系統,無HDFS)
- JupyterHub(支持多用戶的Jupyter notebook)
- pySpark
3. 問題描述
用戶可以正常執行Spark計算,而一旦將Spark結果輸出到本地檔案系統時,就會報錯,比如執行df.write.csv('result'),(注意: 這里的df是Spark DataFrame,不是pandas DataFrame,如果Spark driver有足夠記憶體將結果轉換為pandas DataFrame再保存,是不會出現這個問題的)
報錯分為兩種情況:
- 啟動Spark的為非root用戶時:
java.io.IOException: mkdirs failed to create file - 啟動Spark的為root時:
java.io.IOException: Failed to rename DeprecatedRawLocalFileStatus
會導致結果保存程序中止,無法匯出計算結果
4. 問題分析
問題的根本原因在于啟動Spark的用戶和使用Spark進行計算的用戶不同,其他用戶創建的檔案和檔案夾無法被當前用戶修改:
- 在Spark保存結果時,首先會以提交計算任務的用戶(driver)創建一個檔案夾(比如上文提到的result),該檔案夾的權限為
755(rwxr-xr-x),其他非權限用戶不具有寫權限 - 然后,各個executor會以啟動Spark的用戶在上述檔案夾中寫入臨時結果,如果啟動Spark的用戶不是root,就無法寫入,報第一個錯誤
- 如果啟動Spark的用戶是root,那么臨時結果可以被寫入,最后需要由提交計算任務的用戶(driver)來重新組織,由于這些臨時檔案的所有者是root,所以driver沒有辦法修改,報第二個錯誤
5. 解決思路
解決問題的關鍵在于,在啟動和提交Spark計算用戶不相同的前提下,讓雙方創建的檔案、檔案夾都能夠被雙方修改,問題似乎很簡單,設定一下umask或者ACL不就好了嗎?于是我開始了一些失敗的嘗試:
- 將保存位置的默認ACL檔案夾權限設定為所有人可讀寫
- 將用戶的umask設定為000(所有人可讀寫)
結果發現,在保存Spark結果的時候,這些設定都沒有生效,生成的檔案權限依然為755
這說明Spark有自己的一套配置覆寫了上面的默認配置,那么這個配置在哪呢?
答案是spark.hadoop.fs.permissions.umask-mode,其默認值為022,所以生成的檔案權限依然為755(感謝這位答主),
然而,我以為我的使用環境(本地檔案系統)不適用這個配置項,所以剛開始看到這個答案的時候不以為然直接忽略了…… 后來又折騰了幾個小時,抱著試一試的心態,發現居然成功了
6. 仍存在的問題
- 首先肯定是安全性的問題,用戶的檔案理應只有用戶自己能修改(或者至少是組成員),因為這臺服務器的用戶都是可信的,所以圖省事我把
umask-mode改成了000,稍微安全一點的做法是改成002,然后建立一個(或多個)新組把Spark啟動用戶和計算用戶加入進去 - 即使
umask-mode改成了000,如果啟動Spark的用戶不是root,依然會報第一個錯誤,原因不明 - 有條件、不怕麻煩的話大家還是上HDFS或者其他檔案系統吧,起碼出了問題后能搜到的相關內容都更多些
謹以我昨晚的搜索記錄紀念一下這次debug:

參考資料
- https://spark.apache.org/docs/latest/configuration.html
- https://stackoverflow.com/questions/43077881/spark-how-to-write-files-with-a-given-permission
- https://stackoverflow.com/questions/51769375/how-to-force-spark-hive-to-create-task-directories-with-custom-permissions
- https://www.mail-archive.com/user@spark.apache.org/msg28820.html
- https://stackoverflow.com/a/35987436/6059213
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/437057.html
標籤:其他
上一篇:AWS、Azure等國外云計算如何遷移到國內阿里云上?
下一篇:kafka初學(自己覺得好難)
