hadoop節點字符編碼導致的reduce重複記錄問題排查

1、背景

組內一個同學反饋:reduce輸出目錄中竟然出現了2條重複的key,理論上同一個key只會有一條記錄。程序是通過mr跑的,代碼如下:
這裏寫圖片描述
mapreduce的邏輯很簡單,其實就是實現一個去重。原因是我們的上游日誌裏經常會有重複記錄。爲了保證結果正確,需要將重複記錄去掉。
該同學反饋的這個case中,輸入文件中有2條重複記錄,且在2個不同文件中。

2、問題排查

2.1 判斷是不是不可見字符

首先懷疑該同學眼神不好,畢竟人眼還沒進化到可以識別不可見字符。高度懷疑這2條記錄裏面有不可見字符,看着是一樣的,但其實不一樣。
sql
select md5(line) ,line
from temp_test
where line like '%0001a794d86f0844 %' ;

這裏寫圖片描述
結果發現,兩條記錄md5值是一樣的。好吧,錯怪這名同學了。繼續往下排查。
然後懷疑是partition過程出了問題。如果2個key相同的記錄,partition過程中分到的不同的reduce,那最終的輸出結果裏是有可能出現重複記錄的。

2.2 初步判斷partition過程中有問題

理論上,如果兩個key一樣的話,partition過程會分到同一個reduce裏,2條記錄應該在同一個reduce文件裏(注:每個reduce的輸出都在其編號所對應的part-r-編號文件裏)。
然後查找” 0001a794d86f0844”這條記錄所在的文件位置,結果見下圖,最後一列是文件所在位置。奇怪的是key相同的2條記錄被分到2個不同的reduce。據此可以初步判斷,partition過程中出現了什麼問題,導致同一個key分到了不同的reduce。這裏寫圖片描述

2.3 partition出錯原因分析

同一個key分到不同的reduce,首先第1種可能:自己重寫了partition函數,寫low了。跟該同學瞭解,該同學沒有自定義Partition類,故排除該可能 。
然後看了下hadoop的源碼,Hadoop中默認的Partition類是HashPartitioner,代碼如下。邏輯也比較簡單。沒看出啥問題。
這裏寫圖片描述

看了一會,沒看出是啥原因。然後
突然想起來,處理的日誌當中有中文。於是聯想到 :會不會是因爲hadoop節點的字符編碼不一致,導致不同split的同一個key ,hashcode返回值不一致,計算得到的partition不一樣。決定驗證一下。

2.4 partition出錯驗證

驗證的步驟如下:
1、 修改代碼,修改Mapper類。如下。
1) mapper類裏初始化一個HashPartitioner
2) 修改map的輸出,將parttition編號一塊輸出一下。這裏默認reduce個數爲600。
3) 同時把機器環境打印一下。
這裏寫圖片描述

2、 修改reduce個數爲0。本場景只需要驗證map階段的輸出,不需要用到reduce,故需要將reduce個數設置爲0。
按照上述,修改完之後,重跑程序。然後果然在輸出記錄裏發現(如下圖),這兩條一樣的記錄,分區數一個是373,一個是560.
這裏寫圖片描述
同時也能夠找到對應的hdfs文件。由於hdfs文件的編號和map task的編號一致,根據文件名我們推測,map中07635和07634的機器環境可能不一致。找打對應task,查看日誌(因爲我們的mapper類裏把機器的編碼配置打印到了日誌裏)。

m_007635的輸出:
這裏寫圖片描述

而m_007634的輸出如下。明顯看到兩臺節點上的編碼配置是不一樣的。問題最終定位。
這裏寫圖片描述

3、原因分析及解決方案

可以通過下面方法。

3.1 原因分析

由於hadoop節點編碼不一致,導致在2個節點上執行的同一條記錄,獲取到了不同的partition,被分到了不同的reduce裏,導致了重複記錄。

3.2 解決方案

1種解決方案是要求系統部把節點編碼配置搞成一致。
另1種解決方案是hadoop任務設置參數,加

–D mapred.child.env="LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8"

這個選項,設置任務執行時的編碼。

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