分享在實現一個MapReduce調度器後遇到一些問題的解決過程
將5個WordCount作業通過example中的main函數提交後,沒有使用響應的調度器調度。
問題:通過日誌發現,5個WordCount作業並沒有加入到map隊列當中,隊列爲空,且tasktracker傳回的map
任務個數始終爲0,調查一下原因。
猜測原因1:hadoop默認提交作業到默認隊列,如果要自定義隊列,則需要配置。目前沒有對map和reduce隊列進行配置,因此作業沒有提交到其中。(不是這樣)
解決:根本原因在於由於初始化作業時未獲取到jobTracker的配置,默認爲local,因此使用了localJobRunner類,而非JobTracker類,導致沒有JobTrakcer和調度器等類的日誌輸出。
解決:嘗試更換JobTracker配置的端口號。還是獲取不到。
找到原因:WordCount作業的配置只使用了默認的配置,沒有加載core-site,hdfs-site和mapred-site三個配置文件,導致JobTracker的配置不生效。
解決:將三個配置文件加入到配置對象中,運行正常。
新問題:在從map隊列中remove元素時,作爲鍵的JobSchedulingInfo對象在比較時爲null,經過日誌調試發現,鍵傳入remove函數的參數並不是null,因此嘗試調試隊列中key的內容。
找到原因:並非JobSchedulingInfo對象爲空而是該對象的newPriority字段(自定義的新優先級對象)爲null。在JobSchedulingInfo對象加入隊列時該字段是經過初始化的,那麼就是因爲oldJobSchedulingInfo對象中該字段爲null導致。
解決:在status對象中添加newPriority即可。
新問題:assignTasks方法中有null錯誤,且map隊列的大小一直在增加。
找到原因:因爲在JobSchedulingInfo的compare方法中,比較了jobid和start time的同時也比較了newPriority,比較方法在查找過程中也在用。因此,在刪除過程中由於newPriority的干擾一直找不到對應的對象。
1 final Entry<K,V> getEntryUsingComparator(Object key) {
2 K k = (K) key;
3 // 獲取比較器
4 Comparator<? super K> cpr = comparator;
5 // 其實在調用此方法的get(Object key)中已經對比較器爲null的情況進行判斷,這裏是防禦性的判斷
6 if (cpr != null) {
7 // 獲取根節點
8 Entry<K,V> p = root;
9 // 遍歷樹
10 while (p != null) {
11 // 獲取key和當前節點的key的比較結果
12 int cmp = cpr.compare(k, p.key);
13 // 查找的key值較小
14 if (cmp < 0)
15 // p“移動”到左孩子
16 p = p.left;
17 // 查找的key值較大
18 else if (cmp > 0)
19 // p“移動”到右節點
20 p = p.right;
21 // key值相等
22 else
23 // 返回找到的節點
24 return p;
25 }
26 }
27 // 沒找到key值對應的節點,返回null
28 return null;
29 }
有代碼可見,remove在調用 getEntryUsingComparator(Object key)時使用了比較器的compare方法,由於map的實現是一個樹結構,因此需要頻繁的比較操作,因此compare的定義會影響remove的執行。
奇哉怪也!!!
remove方法竟然不調用compare方法!
調用了其實,只是日誌沒打印。
找到原因:在將job加入map隊列時使用了newPriority的構造器,其中使用作業執行信息重新計算優先級,而開始時這個值被記爲0,這與在JobInProgress對象中保存的初始值(MAX_VALUE)不同,導致優先級比較失敗,在map中找不到scheduling info。
解決:嘗試在構造器中判斷如果是第一次執行,則置爲MAX_VALUE。
針對map和reduce隊列設置不同的優先級字段,比較時使用各自的優先級。初始化時作業類型爲0。在刪除作業後,將刪除的作業對象的優先級更新,以反映到jobTracker的job列表中,保證下一次task在獲取對應job時信息的正確性,否則會導致下一次查找失敗。目前雙隊列機制工作正常。
下一步的工作是保證優先級算法的正確性(尤其是reduce隊列)。