不经意的两行代码把CPU使用率干到了90%+ 没源码怎么排查?

网站建设3年前发布
15 0 0

某同学反映某个应用ECS CPU使用率90%+,希望分析下原因。
该应用使用schedulerx来做定时任务执行,每隔一小时执行一次,每次执行5分钟左右,执行任务期间CPU使用率90%+。
,20230306010420c53238136aaf6a02222515afd9733f5d98e25a908,图1 ECS监控指标,ECS配置是4c8g,从上图来看系统负载已经非常高了。,arthas profiler比较适用CPU使用率持续较高的场景。通过对热点火焰图的分析,NoSuchMethodException异常相关代码占用了很多CPU时间。,20230306010421d94de36032c426ad096499aafd207b68f5f7e2237,图2 热点火焰图,上图红框中NoSuchMethodException展开后如下图:,2023030601042154d615f38e239bf5314514065e0c220e21004f613,图2 异常火焰图,从上图可以看出org.springframework.util.ClassUtils.getStaticMethod调用了Class.getMethod,Class.getMethod抛出了NoSuchMethodException,代码如下。,202303060104228374f6510908112700e0006ab70d35510d1a1f309,图3 ClassUtils.getStaticMethod,为了进一步定位问题,需要知道ClassUtils.getStaticMethod方法的入参:,20230306010601b1fbaff87f980838d80102fa18219a27c8c296786,图4 arthas watch,​从上图看出ClassUtils.getStaticMethod方法入参分别是:**clazz:java.util.Date;_methodName:_valueOf;args[0]:**java.sql.Timestamp。上面图片只是截取了一部分,其中methodName还有of、from。,调用ClassUtils.getStaticMethod的地方是org.springframework.core.convert.support.ObjectToObjectConverter.determineFactoryMethod:​,2023030601042389d9a86382c30a9eb2b821f74fbf779e41c8c8836,图5 ObjectToObjectConverter.determineFactoryMethod,调用ObjectToObjectConverter.determineFactoryMethod的地方是ObjectToObjectConverter.getValidateMember:,20230306010602a27638e23b77d9659b63869a0e36c0d3c3f44b957,图6 ObjectToObjectConverter.getValidateMember,虽然java.sql.Timestamp是java.util.Date的子类,但是从上面代码可以看出进行了很多次无效的调用。,为了更准确的定位相关业务代码,我们需要知道抛出NoSuchMethodException的线程栈,可以使用arthas stack,从线程栈我们可以知道在【哪个类哪个方法哪行】发出的调用。,20230306010603564593923356e81a8f2590f7d0e013944da540340,图7 arthas stack,在我们没有源代码的情况,我们可以使用arthas jad反编译定位到的类,进而分析业务代码,到这里就可以具体定位到问题了。,20230306010603c2a93ca1357a699bddd571ce5cff3ebde1ac96149,图8 业务代码,gmt_created、gmt_modified在实体类中的定义:,2023030601060498a894e964f3346fa0c995b2ef023a58c3a0b7401,图9 业务实体类,查询数据库,数据库返回ResultSet对象。,遍历ResultSet,将ResultSet每一行映射到相应的业务实体类实例化业务实体类,根据ResultSet.getMetaData()获取每一列的值并将该值set到实体类对应属性上在将gmt_created、gmt_modified解析为java.sql.Timestamp类实例,接着使用ObjectToObjectConverter将java.sql.Timestamp转换为java.util.Date的时候抛出了NoSuchMethodException。,异常场景复现示例代码:,20230306010426651e0e572e30f424d2d465d65d8549ab63e32e975,图10 测试代码,20230306010604898486698efa0596d87457ae502167c52adcd3842,图11 测试代码,数据库表中gmt_created、gmt_modified类型与实体类中对应字段类型的定义保持一致,可以解决异常。,通过提高BeanPropertyRowMapper相关逻辑的缓存命中率可以进一步优化性能,如提前将转换逻辑放到GenericConversionService类的converters中:,2023030601042902fea9643f9541cf4482953c028af265fd0d6b535,图12 优化逻辑,另外可以通过自定义RowMapper来提高性能,因为BeanPropertyRowMapper并不是高性能的一种实现:,20230306010428a96bb5f322e178a9309087b83f5f970c6e149c393,图13 BeanPropertyRowMapper

© 版权声明

相关文章