MapReduce中使用字符串拼接导致的问题
2015-02-25 16:09
246 查看
今天在帮业务方优化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使用情况:
[mapred@yz5102 ~]$ 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吧,不要寄希望于底层转换。
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使用情况:
[mapred@yz5102 ~]$ 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吧,不要寄希望于底层转换。
相关文章推荐
- 解决存储过程中拼接的SQL字符串超长导致sql语句被截取的问题
- 利用拼接字符串可能导致SQL注入问题
- printf被编译器优化导致纯字符串打印问题(gcc不使用标准库)
- 使用sem_t导致不能用gdb调试及线程非正常终止后message queue异常的问题
- 使用迅雷导致IIS默认站点无法启动问题的处理
- odbcasvc.exe导致CPU使用100%问题的解决
- odbcasvc.exe导致CPU使用100%问题的解决办法
- ASP.NET基础问题----使用随机字符串
- 几种拼接字符串的效率问题
- 减号拼接字符串的问题
- 使用母版页后,控件名称自动生成导致js无法正常操作.net控件的问题
- 一个有趣的小测试——两个使用字符串描述的二进制数字相或的问题
- 旧话重提---使用FxCop检测出字符串相关的2个问题
- .NET----使用母版页后,控件名称自动生成导致js无法正常操作.net控件的问题
- 转:使用eval()解析JSON格式字符串应注意的问题
- 在ssh框架中使用log4j导致的问题
- 使用hibernate心得——字符串超长的解决办法(setCharacterStream出现顺序问题)
- VC中一个关于宏的使用问题,字符串之间转换,宽字符与普通字符
- PHP字符串拼接语句顺序,导致输出不正常
- policykit-gnome导致unlock不能使用的问题