hadoop使用中的几个小细节

    技术2025-07-22  14

    最近在hadoop实际使用中有以下几个小细节分享: i=m5M]Ef  1 中文问题 KKrLF?rc      从url中解析出中文,但hadoop中打印出来仍是乱码?我们曾经以为hadoop是不支持中文的,后来经过查看源代码,发现hadoop仅仅是不支持以gbk格式输出中文而己。

        这是TextOutputFormat.class中的代码,hadoop默认的输出都是继承自FileOutputFormat来的,FileOutputFormat的两个子类一个是基于二进制流的输出,一个就是基于文本的输出TextOutputFormat。

        public class TextOutputFormat<K, V> extends FileOutputFormat<K, V> { 7(ni_|$|    protected static class LineRecordWriter<K, V> &E{CQ#k      implements RecordWriter<K, V> { ' 7lHWqN<      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) { e(e_p#          throw new IllegalArgumentException(”can’t find ” + utf8 + ” encoding”); LB(I^        } iy<|<*s2D      } n/-nBrVSf  … k-:wM`C      public LineRecordWriter(DataOutputStream out, String keyValueSeparator) { 11'^JmKA        this.out = out; d8)ps,        try { `u</ 4&W          this.keyValueSeparator = keyValueSeparator.getBytes(utf8); :4Gc'b R        } catch (UnsupportedEncodingException uee) { @r.w+E=          throw new IllegalArgumentException(”can’t find ” + utf8 + ” encoding”); j_(DH2D        } Qu x1N      } ab}Kt($  … 0[# zn      private void writeObject(Object o) throws IOException { yt5 Sy        if (o instanceof Text) { Rudj"OGO          Text to = (Text) o; NsPAWI|4          out.write(to.getBytes(), 0, to.getLength());//这里也需要修改 q&DM*!Jq        } else { 5 O't-'          out.write(o.toString().getBytes(utf8)); /80W?9qj        } RXi/&'+H      } 9a6ij*#   … qxQuXF>:#  } |3bCq(ZR/P      可以看出hadoop默认的输出写死为utf-8,因此如果decode中文正确,那么将Linux客户端的character设为utf-8是可以看到中文的。因为hadoop用utf-8的格式输出了中文。 nF)b4`Nd      因为大多数数据库是用gbk来定义字段的,如果想让hadoop用gbk格式输出中文以兼容数据库怎么办? _.{I1*6Y2      我们可以定义一个新的类: .c5)`      public class GbkOutputFormat<K, V> extends FileOutputFormat<K, V> { sTS Nu+    protected static class LineRecordWriter<K, V> #Q]^9/;|4n      implements RecordWriter<K, V> { nOCCOTf  //写成gbk即可 F"ua`ercI      private static final String gbk = “gbk”; T2dv!}7p      private static final byte[] newline; rRQKW_9mB      static { 8Y,imj/(v        try { 0! W$Cz[          newline = “/n”.getBytes(gbk); MS~+P'        } catch (UnsupportedEncodingException uee) { @}<b42          throw new IllegalArgumentException(”can’t find ” + gbk + ” encoding”); X{u/|e{        } k d9<&.y{      } lDX/"Fq  … 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) { _'0C70          throw new IllegalArgumentException(”can’t find ” + gbk + ” encoding”); VK>Cf>        } P;U(2;9 N      } J|aU}Z8m  … /(&UDG$      private void writeObject(Object o) throws IOException { ?0x=ascP        if (o instanceof Text) { $1uT`>%  //        Text to = (Text) o; K"/3/`T  //        out.write(to.getBytes(), 0, to.getLength()); +A-z>T(  //      } else { @h,3"2W{Ev          out.write(o.toString().getBytes(gbk)); IKVFbTX:y        } +`f3_Xd      } isU4D   … eL_Il.:  } U[{vA6      然后在mapreduce代码中加入conf1.setOutputFormat(GbkOutputFormat.class) ;R([w4[~      即可以gbk格式输出中文。

    2 关于计算过程中的压缩和效率的对比问题 hf//2Vl      之前曾经介绍过对输入文件采用压缩可以提高部分计算效率。现在作更进一步的说明。 2GxkOch      为什么压缩会提高计算速度?这是因为mapreduce计算会将数据文件分散拷贝到所有datanode上,压缩可以减少数据浪费在带宽上的时间,当这些时间大于压缩/解压缩本身的时间时,计算速度就会提高了。 (9Of,2]&E      hadoop的压缩除了将输入文件进行压缩外,hadoop本身还可以在计算过程中将map输出以及将reduce输出进行压缩。这种计算当中的压缩又有什么样的效果呢? ?UV|m      测试环境:35台节点的hadoop cluster,单机2 CPU,8 core,8G内存,redhat 2.6.9, 其中namenode和second namenode各一台,namenode和second namenode不作datanode yVe<+Z/7      输入文件大小为2.5G不压缩,records约为3600万条。mapreduce程序分为两个job: ;R]~9Aan      job1:map将record按user字段作key拆分,reduce中作外连接。这样最后reduce输出为87亿records,大小540G q.bx nta"      job2:map读入这87亿条数据并输出,reduce进行简单统计,最后的records为2.5亿条,大小16G <~zPt&C]V      计算耗时54min

        仅对第二个阶段的map作压缩(第一个阶段的map输出并不大,没有压缩的必要),测试结果:计算耗时39min

        可见时间上节约了15min,注意以下参数的不同。 U&W/Nj      不压缩时: o]DYS,v       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 PlR$s       本地读写的的数量大大降低了

         至于对reduce输出的压缩,很遗憾经过测试基本没有提高速度的效果。可能是因为第一个job的输出大多数是在本地机上进行map,不经过网络传输的原因。 {dYz|O<       附:对map输出进行压缩,只需要添加 jobConf.setMapOutputCompressorClass(DefaultCodec.class)

    3 关于reduce的数量设置问题 ?&=JGk^eJ      reduce数量究竟多少是适合的。目前测试认为reduce数量约等于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 3e9UDN2              reduce num=128, reduce time = 2 min M'VJE|+t              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)

    经查明,问题原因是linux机器打开了过多的文件导致。用命令ulimit -n可以发现linux默认的文件打开数目为1024,修改/ect/security/limit.conf,增加hadoop soft 65535

    再重新运行程序(最好所有的datanode都修改),问题解决

    P.S:据说hadoop dfs不能管理总数超过100M个文件,有待查证

    5 运行一段时间后hadoop不能stop-all.sh的问题,显示报错

    no tasktracker to stop ,no datanode to stop

    问题的原因是hadoop在stop的时候依据的是datanode上的mapred和dfs进程号。而默认的进程号保存在/tmp下,linux 默认会每隔一段时间(一般是一个月或者7天左右)去删除这个目录下的文件。因此删掉hadoop-hadoop-jobtracker.pid和 hadoop-hadoop-namenode.pid两个文件后,namenode自然就找不到datanode上的这两个进程了。

    在配置文件中的export HADOOP_PID_DIR可以解决这个问题

    这里还有个文章, 提及了几个hadoop/mapred的优化细节

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

    最新回复(0)