hadoop使用中的幾個小細節

最近在hadoop實際使用中有以下幾個小細節分享:

1 中文問題
    從url中解析出中文,但hadoop中打印出來仍是亂碼?我們曾經以爲hadoop是不支持中文的,後來經過查看源代碼,發現hadoop僅僅是不支持以gbk格式輸出中文而己。

    這是TextOutputFormat.class中的代碼,hadoop默認的輸出都是繼承自FileOutputFormat來的,FileOutputFormat的兩個子類一個是基於二進制流的輸出,一個就是基於文本的輸出TextOutputFormat。

    public class TextOutputFormat<K, V> extends FileOutputFormat<K, V> {
  protected static class LineRecordWriter<K, V>
    implements RecordWriter<K, V> {
    private static final String utf8 = “UTF-8″;//這裏被寫死成了utf-8
    private static final byte[] newline;
    static {
      try {
        newline = “\n”.getBytes(utf8);
      } catch (UnsupportedEncodingException uee) {
        throw new IllegalArgumentException(“can’t find ” + utf8 + ” encoding”);
      }
    }

    public LineRecordWriter(DataOutputStream out, String keyValueSeparator) {
      this.out = out;
      try {
        this.keyValueSeparator = keyValueSeparator.getBytes(utf8);
      } catch (UnsupportedEncodingException uee) {
        throw new IllegalArgumentException(“can’t find ” + utf8 + ” encoding”);
      }
    }

    private void writeObject(Object o) throws IOException {
      if (o instanceof Text) {
        Text to = (Text) o;
        out.write(to.getBytes(), 0, to.getLength());//這裏也需要修改
      } else {
        out.write(o.toString().getBytes(utf8));
      }
    }
 …
}
    可以看出hadoop默認的輸出寫死爲utf-8,因此如果decode中文正確,那麼將Linux客戶端的character設爲utf-8是可以看到中文的。因爲hadoop用utf-8的格式輸出了中文。
    因爲大多數數據庫是用gbk來定義字段的,如果想讓hadoop用gbk格式輸出中文以兼容數據庫怎麼辦?
    我們可以定義一個新的類:
    public class GbkOutputFormat<K, V> extends FileOutputFormat<K, V> {
  protected static class LineRecordWriter<K, V>
    implements RecordWriter<K, V> {
//寫成gbk即可
    private static final String gbk = “gbk”;

    private static final byte[] newline;
    static {
      try {
        newline = “\n”.getBytes(gbk);
      } catch (UnsupportedEncodingException uee) {
        throw new IllegalArgumentException(“can’t find ” + gbk + ” encoding”);
      }
    }

    public LineRecordWriter(DataOutputStream out, String keyValueSeparator) {
      this.out = out;
      try {
        this.keyValueSeparator = keyValueSeparator.getBytes(gbk);
      } catch (UnsupportedEncodingException uee) {
        throw new IllegalArgumentException(“can’t find ” + gbk + ” encoding”);
      }
    }

    private void writeObject(Object o) throws IOException {
      if (o instanceof Text) {
//        Text to = (Text) o;
//        out.write(to.getBytes(), 0, to.getLength());
//      } else {

        out.write(o.toString().getBytes(gbk));
      }
    }
 …
}
    然後在mapreduce代碼中加入conf1.setOutputFormat(GbkOutputFormat.class)
    即可以gbk格式輸出中文。

2 關於計算過程中的壓縮和效率的對比問題
    之前曾經介紹過對輸入文件採用壓縮可以提高部分計算效率。現在作更進一步的說明。
    爲什麼壓縮會提高計算速度?這是因爲mapreduce計算會將數據文件分散拷貝到所有datanode上,壓縮可以減少數據浪費在帶寬上的時間,當這些時間大於壓縮/解壓縮本身的時間時,計算速度就會提高了。
    hadoop的壓縮除了將輸入文件進行壓縮外,hadoop本身還可以在計算過程中將map輸出以及將reduce輸出進行壓縮。這種計算當中的壓縮又有什麼樣的效果呢?
    測試環境:35臺節點的hadoop cluster,單機2 CPU,8 core,8G內存,redhat 2.6.9, 其中namenode和second namenode各一臺,namenode和second namenode不作datanode
    輸入文件大小爲2.5G不壓縮,records約爲3600萬條。mapreduce程序分爲兩個job:
    job1:map將record按user字段作key拆分,reduce中作外連接。這樣最後reduce輸出爲87億records,大小540G
    job2:map讀入這87億條數據並輸出,reduce進行簡單統計,最後的records爲2.5億條,大小16G
    計算耗時54min

    僅對第二個階段的map作壓縮(第一個階段的map輸出並不大,沒有壓縮的必要),測試結果:計算耗時39min

    可見時間上節約了15min,注意以下參數的不同。
    不壓縮時:
     Local bytes read=1923047905109
     Local bytes written=1685607947227
     壓縮時:
     Local bytes read=770579526349
     Local bytes written=245469534966
     本地讀寫的的數量大大降低了

     至於對reduce輸出的壓縮,很遺憾經過測試基本沒有提高速度的效果。可能是因爲第一個job的輸出大多數是在本地機上進行map,不經過網絡傳輸的原因。
     附:對map輸出進行壓縮,只需要添加jobConf.setMapOutputCompressorClass(DefaultCodec.class)

3 關於reduce的數量設置問題
    reduce數量究竟多少是適合的。目前測試認爲reduce數量約等於cluster中datanode的總cores的一半比較合適,比如cluster中有32臺datanode,每臺8 core,那麼reduce設置爲128速度最快。因爲每臺機器8 core,4個作map,4個作reduce計算,正好合適。
    附小測試:對同一個程序
            reduce num=32,reduce time = 6 min
            reduce num=128, reduce time = 2 min
            reduce num=320, reduce time = 5min

參考:http://www.alidata.org/archives/244/comment-page-1#comment-5644

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