ps -mp 733 -o THREAD,tid,time | sort -rn
线程ID转换为16进制格式
printf "%x\n" 775
查看java 的堆栈信息
jstack 733 |grep 307 -A 30
显然是 SmsQueueServiceImpl 中的produceMissSms 和 consumeMissSms 方法有问题
一下为精简的部分代码
/**
* Created by dongxc on 2015/7/7. 通知消息队列
*/
@Service("smsQueueService")public classSmsQueueServiceImpl {//生产异常队列方法
public voidproduceMissSms(SmsLogDo smsLogDo) {/** try{ String key = EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue(); boolean result = redisService.lpush(key,
* smsLogDo, 0); if(result==false){ logger.error("通知消息异常队列生产消息返回失败!"+smsLogDo.getId()); } }catch(Exception e){
* logger.error("通知消息异常队列生产消息失败!", e); }*/}//消费异常队列方法
publicSmsLogDo consumeMissSms() {try{
String destKey=EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue();
SmsLogDo smsLogDo= newSmsLogDo();
Object obj= null;if (obj == null) {return null;
}else{
smsLogDo=(SmsLogDo) obj;
}returnsmsLogDo;
}catch(Exception e) {
logger.error("通知消息队列消费方法失败!", e);return null;
}
}
}
从很有年代感的垃圾代码来看 这两个方法并没有什么问题 继续往调用这两个方法的上层排查
/*** Created by dongxc on 2015/7/7.
* 消息通知监控线程*/@Service("smsMonitorComsumer")public classSmsMonitorComsumerImpl {
@AutowiredprivateSmsQueueServiceImpl smsQueueService;//取队列里的任务消费
@Transactional(propagation=Propagation.NOT_SUPPORTED)public voidrun() {while (true) {try{
SmsLogDo smsLogDo=smsQueueService.consumeMissSms();
Boolean result= false;if(smsLogDo!=null){long diff = (new Date()).getTime() -smsLogDo.getSendtime().getTime() ;long min = diff%(1000*24*60*60)%(1000*60*60)/(1000*60);//计算差多少分钟
if(min>5){
result= true;
}
}if(result){
smsQueueService.produceSms(smsLogDo);
}else{
smsQueueService.produceMissSms(smsLogDo);
}
}catch(Exception ex) {try{
Thread.sleep(3000);
}catch(Exception e){//logger.error("发送站内信息短信时线程执行失败2!", e);
}
}
}
}
}
很显然 这里有一个while(true) 无数个草泥马策马奔腾 ps:垃圾代码看多了, 我已经不愤怒了.
基本定位到问题了 while里面完全是没有用的代码
继续往上层看谁来调用
/*** Created by dongxc on 2015/7/7.
* 通知消息队列*/@Service("smsLogRunThread")public classSmsLogRunThreadImpl {public intflag;
@AutowiredprivateSmsLogConsumerImpl smsLogConsumer;
@AutowiredprivateSmsMonitorComsumerImpl smsMonitorComsumer;
@PostConstructpublic voidinit() {if(ip!=""&&host!=""&&ip.equals(host)){
Thread thread= newThread(){public voidrun() {
smsLogConsumer.run();
}
};
thread.start();
Thread thread1= newThread(){public voidrun() {
smsMonitorComsumer.run();
}
};
thread1.start();
}
}
}
在应用一启动的时候 spring初始化的就会执行这一段处理丢失消息的代码 然后这段死循环代码 没有任何作用
解决方法 即 注释掉whlie(true)这一段代码
重新部署后 cpu占用就很正常了
案例一下,其实之前也遇到过CPU占用很高的问题, 但是那次是 频繁的GC导致的
其实排查问题 的过程中也是在不断的学习的过程 ! 先打个鸡血,我要继续搬砖了