隨筆-314  評論-209  文章-0  trackbacks-0

          最近在hadoop實際使用中有以下幾個小細節(jié)分享: i=m5M]Ef  
          1 中文問題 
              從url中解析出中文,但hadoop中打印出來仍是亂碼?我們曾經(jīng)以為hadoop是不支持中文的,后來經(jīng)過查看源代碼,發(fā)現(xiàn)hadoop僅僅是不支持以gbk格式輸出中文而己。

              這是TextOutputFormat.class中的代碼,hadoop默認的輸出都是繼承自FileOutputFormat來的,F(xiàn)ileOutputFormat的兩個子類一個是基于二進制流的輸出,一個就是基于文本的輸出TextOutputFormat。

              public class TextOutputFormat<K, V> extends FileOutputFormat<K, V> { 
            protected static class LineRecordWriter<K, V> &E{CQ#k  
              implements RecordWriter<K, V> { 
              private static final String utf8 = “UTF-8″;//這里被寫死成了utf-8 2 kP0//  
              private static final byte[] newline; kTC'`xv  
              static { :htz]  
                try { 0 _!')+  
                  newline = “/n”.getBytes(utf8); Ry$zF~[   
                } catch (UnsupportedEncodingException uee) { 
                  throw new IllegalArgumentException(”can’t find ” + utf8 + ” encoding”); 
                } 
              } 
          k-:wM`C  
              public LineRecordWriter(DataOutputStream out, String keyValueSeparator) { 
                this.out = out; 
                try { 
                  this.keyValueSeparator = keyValueSeparator.getBytes(utf8); 
                } catch (UnsupportedEncodingException uee) { @r.w+E=  
                  throw new IllegalArgumentException(”can’t find ” + utf8 + ” encoding”); 
                } 
              } ab}Kt($  
          … 
              private void writeObject(Object o) throws IOException { 
                if (o instanceof Text) { 
                  Text to = (Text) o; 
                  out.write(to.getBytes(), 0, to.getLength());//這里也需要修改 q&DM*!Jq  
                } else { 5 O't-'  
                  out.write(o.toString().getBytes(utf8)); 
                } 
              } 
           … qxQuXF>:#  
          } |3bCq(ZR/P  
              可以看出hadoop默認的輸出寫死為utf-8,因此如果decode中文正確,那么將Linux客戶端的character設為utf-8是可以看到中文的。因為hadoop用utf-8的格式輸出了中文。 
              因為大多數(shù)數(shù)據(jù)庫是用gbk來定義字段的,如果想讓hadoop用gbk格式輸出中文以兼容數(shù)據(jù)庫怎么辦? _.{I1*6Y2  
              我們可以定義一個新的類: .c5)`  
              public class GbkOutputFormat<K, V> extends FileOutputFormat<K, V> { sTS Nu+  
            protected static class LineRecordWriter<K, V> 
              implements RecordWriter<K, V> { 
          //寫成gbk即可 F"ua`ercI  
              private static final String gbk = “gbk”;
           
              private static final byte[] newline; 
              static { 
                try { 
                  newline = “/n”.getBytes(gbk); 
                } catch (UnsupportedEncodingException uee) { @}<b42  
                  throw new IllegalArgumentException(”can’t find ” + gbk + ” encoding”); 
                } 
              } 
          SjL&/),  
              public LineRecordWriter(DataOutputStream out, String keyValueSeparator) { P?o|N<46  
                this.out = out; X-<l+WP  
                try { 0,]m.)ws  
                  this.keyValueSeparator = keyValueSeparator.getBytes(gbk); Js'j}w  
                } catch (UnsupportedEncodingException uee) { 
                  throw new IllegalArgumentException(”can’t find ” + gbk + ” encoding”); 
                } 
              } J|aU}Z8m  
          /(&UDG$  
              private void writeObject(Object o) throws IOException { 
                if (o instanceof Text) { 
          //        Text to = (Text) o; 
          //        out.write(to.getBytes(), 0, to.getLength()); +A-z>T(  
          //      } else {
          @h,3"2W{Ev  
                  out.write(o.toString().getBytes(gbk)); 
                } 
              } isU4D  
           … eL_Il.:  

              然后在mapreduce代碼中加入conf1.setOutputFormat(GbkOutputFormat.class) 
              即可以gbk格式輸出中文。

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

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

              可見時間上節(jié)約了15min,注意以下參數(shù)的不同。 U&W/Nj  
              不壓縮時: 
               Local bytes read=1923047905109 :3[;9xCHj  
               Local bytes written=1685607947227 "j8`)XXa(  
               壓縮時: /U>|^$4 #5  
               Local bytes read=770579526349 |RL/2j|  
               Local bytes written=245469534966 
               本地讀寫的的數(shù)量大大降低了

               至于對reduce輸出的壓縮,很遺憾經(jīng)過測試基本沒有提高速度的效果。可能是因為第一個job的輸出大多數(shù)是在本地機上進行map,不經(jīng)過網(wǎng)絡傳輸?shù)脑颉?nbsp;
               附:對map輸出進行壓縮,只需要添加 jobConf.setMapOutputCompressorClass(DefaultCodec.class)

          3 關于reduce的數(shù)量設置問題 
              reduce數(shù)量究竟多少是適合的。目前測試認為reduce數(shù)量約等于cluster中datanode的總cores的一半比較合適,比如 cluster中有32臺datanode,每臺8 core,那么reduce設置為128速度最快。因為每臺機器8 core,4個作map,4個作reduce計算,正好合適。 u/(>a  
              附小測試:對同一個程序 j&[u$P*K  
                      reduce num=32,reduce time = 6 min 
                      reduce num=128, reduce time = 2 min 
                      reduce num=320, reduce time = 5min

           

          4某次正常運行mapreduce實例時,拋出錯誤

          java.io.IOException: All datanodes xxx.xxx.xxx.xxx:xxx are bad. Aborting…

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream.processDatanodeError(DFSClient.java:2158)

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream.access$1400(DFSClient.java:1735)

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream$DataStreamer.run(DFSClient.java:1889)

          java.io.IOException: Could not get block locations. Aborting…

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream.processDatanodeError(DFSClient.java:2143)

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream.access$1400(DFSClient.java:1735)

          at org.apache.hadoop.dfs.DFSClient$DFSOutputStream$DataStreamer.run(DFSClient.java:1889)

          經(jīng)查明,問題原因是linux機器打開了過多的文件導致。用命令ulimit -n可以發(fā)現(xiàn)linux默認的文件打開數(shù)目為1024,修改/ect/security/limit.conf,增加hadoop soft 65535

          再重新運行程序(最好所有的datanode都修改),問題解決

          P.S:據(jù)說hadoop dfs不能管理總數(shù)超過100M個文件,有待查證

          5 運行一段時間后hadoop不能stop-all.sh的問題,顯示報錯

          no tasktracker to stop ,no datanode to stop

          問題的原因是hadoop在stop的時候依據(jù)的是datanode上的mapred和dfs進程號。而默認的進程號保存在/tmp下,linux 默認會每隔一段時間(一般是一個月或者7天左右)去刪除這個目錄下的文件。因此刪掉hadoop-hadoop-jobtracker.pid和 hadoop-hadoop-namenode.pid兩個文件后,namenode自然就找不到datanode上的這兩個進程了。

          在配置文件中的export HADOOP_PID_DIR可以解決這個問題

          這里還有個文章, 提及了幾個hadoop/mapred的優(yōu)化細節(jié)

          http://thethethethethethe.spaces.live.com/blog/cns!A001241972EA08EA!228.entry

          posted on 2013-10-17 17:14 xzc 閱讀(4718) 評論(0)  編輯  收藏 所屬分類: hadoop
          主站蜘蛛池模板: 龙里县| 安丘市| 乌拉特中旗| 固原市| 泰来县| 勃利县| 湛江市| 鄂尔多斯市| 蒙自县| 内丘县| 南昌县| 孝昌县| 万州区| 贵州省| 陕西省| 历史| 清徐县| 乌审旗| 呼和浩特市| 太仓市| 江阴市| 历史| 阳朔县| 乐业县| 长丰县| 洛浦县| 鱼台县| 滁州市| 中西区| 玛曲县| 龙川县| 昆山市| 蕲春县| 罗城| 沂南县| 天峻县| 隆尧县| 淄博市| 烟台市| 利津县| 靖西县|