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

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

              這是TextOutputFormat.class中的代碼,hadoop默認(rèn)的輸出都是繼承自FileOutputFormat來的,F(xiàn)ileOutputFormat的兩個子類一個是基于二進(jìn)制流的輸出,一個就是基于文本的輸出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默認(rèn)的輸出寫死為utf-8,因此如果decode中文正確,那么將Linux客戶端的character設(shè)為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 關(guān)于計算過程中的壓縮和效率的對比問題 hf//2Vl  
              之前曾經(jīng)介紹過對輸入文件采用壓縮可以提高部分計算效率?,F(xiàn)在作更進(jìn)一步的說明。 
              為什么壓縮會提高計算速度?這是因為mapreduce計算會將數(shù)據(jù)文件分散拷貝到所有datanode上,壓縮可以減少數(shù)據(jù)浪費在帶寬上的時間,當(dāng)這些時間大于壓縮/解壓縮本身的時間時,計算速度就會提高了。 
              hadoop的壓縮除了將輸入文件進(jìn)行壓縮外,hadoop本身還可以在計算過程中將map輸出以及將reduce輸出進(jìn)行壓縮。這種計算當(dāng)中的壓縮又有什么樣的效果呢? 
              測試環(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進(jìn)行簡單統(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ù)是在本地機上進(jìn)行map,不經(jīng)過網(wǎng)絡(luò)傳輸?shù)脑颉?nbsp;
               附:對map輸出進(jìn)行壓縮,只需要添加 jobConf.setMapOutputCompressorClass(DefaultCodec.class)

          3 關(guān)于reduce的數(shù)量設(shè)置問題 
              reduce數(shù)量究竟多少是適合的。目前測試認(rèn)為reduce數(shù)量約等于cluster中datanode的總cores的一半比較合適,比如 cluster中有32臺datanode,每臺8 core,那么reduce設(shè)置為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機器打開了過多的文件導(dǎo)致。用命令ulimit -n可以發(fā)現(xiàn)linux默認(rèn)的文件打開數(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進(jìn)程號。而默認(rèn)的進(jìn)程號保存在/tmp下,linux 默認(rèn)會每隔一段時間(一般是一個月或者7天左右)去刪除這個目錄下的文件。因此刪掉hadoop-hadoop-jobtracker.pid和 hadoop-hadoop-namenode.pid兩個文件后,namenode自然就找不到datanode上的這兩個進(jìn)程了。

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

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

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

          posted on 2013-10-17 17:14 xzc 閱讀(4718) 評論(0)  編輯  收藏 所屬分類: hadoop
          主站蜘蛛池模板: 株洲市| 九龙坡区| 仁化县| 琼海市| 北京市| 旬阳县| 惠安县| 芦山县| 香格里拉县| 南汇区| 东兴市| 黔南| 巨野县| 邵阳市| 十堰市| 山东省| 临海市| 罗城| 宣城市| 阜新| 潼南县| 怀宁县| 平利县| 遂昌县| 莎车县| 遂溪县| 鸡西市| 灵山县| 乌拉特前旗| 宣威市| 丹东市| 武宁县| 屏山县| 特克斯县| 宣汉县| 平利县| 麟游县| 仁布县| 若羌县| 澎湖县| 富源县|