记录一次java进程cpu占用过高问题排查

问题描述:

新版本灰度升级后,调用一个新接口,马上cpu会飙升到100+,并且实例再无响应,并且过几分钟后,cpu占用率会降下来,但是实例无法再提供服务,并且进程并没有死亡。

环境:

jdk:1.8
spring cloud: Daltson.RELEASE

排查办法:

  • 1.查看此实例的进程号:top命令
  • 2.查看此进程中占用最高的线程:ps -mp pid -o THREAD,tid,time
  • 3.将线程号转换成16进制:printf "%x\n" (上面命令看到的占用过高线程号)
  • 4.查看线程的堆栈信息:jstack pid | grep tid 此时发现,占用最高的两个线程,全部是gc线程。
  • 5.继续查看gc情况:jstat -gcutil ,重启服务实例后,调用接口,cpu马上占用率飙高,用jstat命令查看到,这过程中fullGC达到300多次。明显此接口的一些操作引起了大量的对象堆积到内存中,导致内存爆掉了。
  • 6.继续查看出现问题时,内存的占用情况,我选择查看内存中的对象的大小:jmap -heap >heap.txt jmap -histo > histo.txt
  • 7.查看上面两个文件后终于发现了问题,调用此接口会产生大量的LinkedList对象和sharding-jdbc中的shardingPrepareStatment对象,这两个对象加起来将近占用了800m的内存,难怪会卡死。

问题原因:

后面就通过排查代码,跟踪数据,发现此问题是由于特殊的查询条件引起的sharding-jdbc出现了bug。
出现的原因如下代码示例:

  <select id="selectByCondition" resultMap="BaseResultMap">
        select ID, `NAME`, SEX , SHARDING_ID
        from mem_user
        <where>
        	1=1
        	<if test="id != null">
        		AND ID=#{id},
        	</if>
        	<if test="name != null and name != ''">
        		AND NAME=#{name},
        	</if>
        	<if test="ids != null">
        		AND ID in
        		<foreach item="item" index="index" collection="ids"
    		      open="(" separator="," close=")">
    		        #{item}
    		  </foreach>
        	</if>
        	<if test="sex != null">
        		AND SEX=#{sex},
        	</if>
        	AND COMPANY_ID = #{companyId}
        </where>
      </select>

查询条件:

 Map<String,Object> param = new HashMap<String,Object>();
List<Long> ids = new ArrayList<Long>(1);
ids.add(null);
param.put("ids",ids);
param.put("companyId",1L);
List<MemUser> userList = this.userService.getByCondition(param);

可以看到上面的代码会产生select * from mem_user_1 in (null),这样的sql,只有此种情况下才会引起此问题。
公司使用的sharding-jdbc版本为2.0.0,后来自己回家用代码测试,因为我自己使用的是最新的3.0.0.M4,经测试已经无此问题。

猜你喜欢

转载自blog.csdn.net/u013057846/article/details/83243357