今天在帮业务方优化mapreduce作业时遇到一个用字符串拼接的问题。
reduce中字符串拼接代码:
while (it.hasNext()) { line = it.next().toString(); artID+=line+","; ct++; }
采用的是String直接拼接,结果是该作业作业只剩一个reduce一直在运行,而且时间长达6小时,其他已经完成的reduce只用了10多分钟。
咨询了一下业务方,artID有的会很长,这个时候会一直进行字符串拼接。
我又看了一下未完成和已完成的reduce处理的数据量差别不大,未完成的需要处理60M的数据,已完成的处理了50M的数据。
1、查看该reduce的java进程的堆内存使用情况,不存在堆内存不够用,导致一直FGC的情况。
2、查看该reduce的java进程的cpu使用情况:
[[email protected] ~]$ top -p 39257 top - 14:48:37 up 393 days, 20:34, 2 users, load average: 8.75, 15.84, 15.53 Tasks: 43 total, 1 running, 42 sleeping, 0 stopped, 0 zombie Cpu(s): 28.8%us, 7.2%sy, 0.0%ni, 61.7%id, 0.9%wa, 0.0%hi, 1.3%si, 0.0%st Mem: 49374704k total, 41905644k used, 7469060k free, 2167520k buffers Swap: 8388600k total, 341168k used, 8047432k free, 27925176k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 39258 mapred 20 0 2432m 1.6g 15m R 94.1 3.4 303:47.63 java 39263 mapred 20 0 2432m 1.6g 15m S 5.7 3.4 11:31.72 java 39265 mapred 20 0 2432m 1.6g 15m S 5.3 3.4 11:32.03 java 39268 mapred 20 0 2432m 1.6g 15m S 5.3 3.4 11:34.02 java 39271 mapred 20 0 2432m 1.6g 15m S 5.3 3.4 11:32.73 java
发现39258这个线程的cpu使用率很高。
打印出该reduce的java进程的线程堆栈信息并找到39258线程相关的信息,39258的十六进制为0x995a,找到nid=0x995a的线程就可以了:
"main" prio=10 tid=0x00007f36e000d000 nid=0x995a runnable [0x00007f36e6ab6000] java.lang.Thread.State: RUNNABLE at java.util.Arrays.copyOfRange(Arrays.java:3209) at java.lang.String.<init>(String.java:215) at java.lang.StringBuilder.toString(StringBuilder.java:430) at weMedia.create.ArticleInfoReduce.reduce(ArticleInfoReduce.java:23) at weMedia.create.ArticleInfoReduce.reduce(ArticleInfoReduce.java:13) at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:171) at org.apache.hadoop.mapred.ReduceTask.runNewReducer(ReduceTask.java:627) at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:389) at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:167) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:396) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1550) at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:162)
线程堆栈信息显示,该线程cpu使用率高是因为一直在进行字符串拼接,虽然代码直接使用的是String,但是JVM底层转化成了StringBuilder的操作,按理说转换成了StringBuilder效果不应该低,但是实际结果并不理想。
最后让业务方显示的修改了字符串拼接部分的代码,使用StringBuffer,重新执行了一下该作业,作业全部运行完成只用了10多分钟,和修改之前的6个小时,运行效率提高了很多倍。
小结:
虽然直接用String拼接,底层实际使用的是StringBuilder进行操作,但是效率还是不尽人意,最好还是显示的用StringBuilder或者StringBuffer吧,不要寄希望于底层转换。
时间: 2024-10-28 15:16:42