【spark】on yarn的模式下,如何上傳files並在程序中讀取到?

在使用spark的時候,往往我們需要外部傳入文件,來配合程序做數據處理

那麼這就涉及到,如何傳入,如何獲取(本文討論的是spark on yarn

講實話,我覺得這個問題挺煩的,我百度了好久(可能我姿勢不對?),各種博客,stackoverflow,community.cloudera.com都找過,我覺得回答方都停留在理論基礎,並沒有show me code,我實際測試的時候,好像又和他們說的不太一樣,哎,要是能有統一的入口,統一的出口就好了

 

1、client模式

client模式下,driver開啓在提交任務的機器上,所以他可以直接讀取到本地的文件,這就很簡單了

(1)、從shell中傳入文件的絕對路徑(關鍵在spark.filename這一行)

bin/spark-submit \
--master yarn \
--class spark.LoadFileTest \
--deploy-mode client \
--conf spark.file.absolutepath=/opt/data/sql.txt \
/opt/CDH/spark-2.2.0-bin-2.6.0-cdh5.12.1/spark.jar 

其實隨便找個名字,不一定要用spark.file.absolutepath來作爲參數名稱,但是你的參數名稱必須是spark開頭的,纔會被sparkConf加載

 (2)、在代碼中獲取到shell傳入的路徑,然後通過java的io流讀取數據

public static void main(String[] args)  {
        SparkSession sparkSession = buildSparkSession(false, "LoadFileTest");
        String absolutePath = sparkSession.conf().get("spark.file.absolutepath");
        System.out.println("===============文件絕對路徑=================");
        System.out.println("absolutePath = "+ absolutePath);
    
        String sql = readFileContent(absolutePath);
        System.out.println("文件內容 = "+ sql);
    }

private static String readFileContent(String absolutePath) {
        BufferedReader reader = null;
        StringBuffer stringBuffer = new StringBuffer();
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(absolutePath)));
            String str;
            //一次讀取一行
            while ((str = reader.readLine()) != null) {
                stringBuffer.append(str + "\n");
            }
        } catch (Exception e) {
           e.printStackTrace();
            return null;
        }
        return stringBuffer.toString();
    }

(3)、獲得了之後想幹嘛就幹嘛吧,如果想讓executor處理的時候也用到這個數據,可以把這個數據做爲廣播變量廣播出去就好了

2、cluster模式

cluster模式下,driver會在任意有資源的節點啓動,那麼他就讀取不到當前提交任務的這臺機器的數據了,所以理論上,我們需要提供一個分佈式的文件系統,讓所有機器都可以通過這個系統獲取數據

(1)、在shell中使用--files的方式上傳文件,並且還要傳入文件名

bin/spark-submit \
--master yarn \
--class spark.LoadFileTest \
--deploy-mode client \
--conf spark.filename=sql.txt \
--files /opt/sql.txt  \
/opt/CDH/spark-2.2.0-bin-2.6.0-cdh5.12.1/spark.jar 

通過以上shell,你會發現日誌中有一條info,把本地的文件上傳到了hdfs上,這樣就可以通過hdfs訪問這個數據

 

(2)、代碼中獲取

可以通過spark的read直接讀數據,也可以自己寫io流讀取hdfs上的文件,這裏我選的第一種,比較方便

public static void main(String[] args)  {
        SparkSession sparkSession = buildSparkSession(false, "LoadFileTest");
        String fileName= sparkSession.conf().get("spark.file.absolutepath");
        System.out.println("===============文件名=================");
        System.out.println("fileName= "+ fileName);
        Dataset<String> confSql = spark
                .read()
                .textFile(System.getenv("SPARK_YARN_STAGING_DIR") + "/" + fileName);

        confSql.show(false);
        //這裏可以通過take,collect等方法,把Dataset的中的數據取出轉成String
        //由於太簡單我就不寫了

    }

有同學會問,誒,你這個SPARK_YARN_STAGING_DIR哪裏來的呀?

通過cluster提交的任務,我們無法在提交的機器直接看到日誌,所以我的hadoop開啓了jobhistory服務之後,我運行如下查看日誌的命令

bin/yarn logs -applicationId 這裏傳入具體的$application_id

 

3、備註

另我覺得煩的事情是這樣的,我在想,有沒有統一的方法,不管是client還是cluster都可以使用這個方法讀取數據

不知道是就沒有這樣的方法,還是我找不到

你看,理論上來說,client模式,我也通過--files把文件上傳到hdfs上,然後讀取hdfs上的數據就好了呀,但是關鍵在於client模式下,SPARK_YARN_STAGING_DIR居然爲null,這實在太難受了。。。。那我就不能方便的得到--files上傳的數據的目錄了,所以client模式我纔會用io直接讀取本地文件,不知道各位老哥們有沒有解決這個問題的方法呢?

 

所以如果不確定用戶提及shell中,會使用client還是cluster,那代碼中,只能先加一層判斷,判斷sparkSession.conf().get("spark.submit.deployMode")這個值是client還是cluster,然後再調用對應模式下的文件的讀取,想想就覺得好煩啊!

好了菜雞一隻,下次再見!

馬上端午節加上我的生日到了,提前祝自己生日快樂吧!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章