MapReduce中使用字符串拼接导致的问题

今天在帮业务方优化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

MapReduce中使用字符串拼接导致的问题的相关文章

【SQL】小心字符串拼接导致长度爆表

原文:[SQL]小心字符串拼接导致长度爆表 请看代码: DECLARE @max VARCHAR(max) SET @max='aaa...' --这里有8000个a +'bb' --连接一个varchar常量或变量 SELECT LEN(@max) 别想当然以为它会返回8002,而是8000,select @max也只会得到8000个a,后面两个b没了.我们知道,varchar(max)类型不受字符数限制,但为什么会这样? 这其实与@max的数据类型无关,而是与字符串拼接后得到的数据类型有关,

golang中的字符串拼接

go语言中支持的字符串拼接的方法有很多种,这里就来罗列一下 常用的字符串拼接方法 1.最常用的方法肯定是 + 连接两个字符串.这与python类似,不过由于golang中的字符串是不可变的类型,因此用 + 连接会产生一个新的字符串对效率有影响. s1 := "字符串" s2 := "拼接" s3 := s1 + s2 fmt.Print(s3) //s3 = "打印字符串" 2.第二种方法使用sprintf函数,虽然不会像直接使用 + 那样产生临

python中实现字符串使用非&quot;+&quot;号拼接的方式实现

在脉脉上看到一片在程序中对字符串拼接的实现,不用+号如何完成字符串拼接,大概看了下评论,大部分都是说在java中实现不使用+号,完成字符串的拼接操作,在此之前我也是安装以往经验for循环遍历列表使用+号完成字符串拼接操作,今天尝试使用非+号完成字符串的拼接操作,一下拼接一个条件sql的拼接实现 例句sql是链接到hive库进行的查询操作代码如下 imsis = ('460020291****15', '46002029****6391') # 构造新数列 # i = "(" # for

[Java Performance] 字符串拼接注意事项

字符串拼接(String Concatenation) // 编译器优化前 String answer = integerPart + "." + mantissa; // 编译器优化后 String answer = new StringBuilder(integerPart).append(".").append(mantissa).toString(); 因为编译器会对字符串的拼接操作进行优化,所以在同一条语句中使用字符串拼接操作对性能并没有负面影响.正因为编

lua基础【二】lua中关于字符串的操作总结

--从从控制台输入字符串操作 str =io.read() if str=="hello" then print(str) end --lua中的字符串拼接操作 str="hello" str2="world" str3=str..str2 print(str3) --lua中的number与string类型的转换 a=10 b=tostring(a) if b == "10" then print(b) end c=tonu

3、python中的字符串

一.前言 字符串是python中重要的数据类型.字符串就是一段文本,在python中用引号来标示. 二.字符串分类 字符串根据使用场景不同,一共分成3类: (1)单引号.双引号创建的单行字符串: 在单引号和双引号的单行字符串中不能通过回车键换行,在python shell ide中会直接执行命令,在某些编辑器中会帮你转成两行的单行字符串.如果想要在单行字符串中换行,只能通过在字符串输入\n,不过不建议这么做. 示例1: 示例2: 这里在光标所在位置换行,直接帮你另开一个换行字符串提示你输入,在换

mysql 字符串拼接+设置null值

#字符串拼接 concat(s1,s2); 将表中last_name和first_name中的字符串拼接 select concat(last_name,first_name) as 姓名 from employees; #只会修改last_name不会修改first_name SELECT first_name,last_name AS f FROM employees; #将两个列用逗号隔开并命名为out_put SELECT CONCAT(`last_name`,',',`phone_nu

解决存储过程中拼接的SQL字符串超长导致sql语句被截取的问题

今天遇到了一个奇葩的问题:存储过程中的sql字符串拼接的太长,超出了分页存储过程执行sql参数的nvarchar(4000)的长度. 没办法,只能修改自己的存储过程,因为分页存储过程是不能动的. 开始想到的方法是将里层的select语句抽出来,用exec(strInnerSql)执行,将查询胡来的数据放到临时表中,在@s中用临时表获取数据,结果以时报告终 错误原因:执行@s语句的时候找不到执行exec(strInnerSql)产生的临时表 好郁闷啊,怎么会这样呢,明明在一个存储过程中执行的,怎么

python中字符串拼接

python中字符串拼接的三种方式: 1.使用 '+': 这中方式会在内存中,没使用一次就开辟一个新的空间,不建议使用.当数据庞大时候效率很低.后期有垃圾回收机制来处理没有用的字符串 案例:name = 'jam' name1 = name + 'c'这样内存中会开辟一个空间存放 name2 = name1 + 'h''这样内存中会再开辟一个空间存放 2.字符串格式化的形式:%s,这中方式让内存最多就开辟两个空间来进行存放字符. 案例:name = 'jam' name2 = 'chen' se