CPU瞬间飙升170%问题复盘

现象

做消息转发的服务(业务服务器),当收到一个请求触发时,CPU飙升170%+,导致请求响应时间漫长。

现象描述

TOP查看服务器进程

问题排查思路

代码逻辑复杂,导致处理时间过长

主业务代码体中加入调用时间日志打印,发现处理时间非常短,排除此项。

网络阻塞导致调用时间长(刚开始一直以为的问题)

测试同区域服务器互ping时间,时间很短,基本排除
ping服务器ip

定位线程(网上常用方法)

top 查看占用cpu最多的进程号
ps -mp 24939 -o THREAD,tid,time c 查看该进程的线程情况
并未发现异常线程
结果发现两个线程cpu瞬间占用70%+(截图是后边复盘截取,不是当时情况)

查找问题线程

  1. 挑选TID为24471的线程,查看该线程的堆栈情况,先将线程id转为16进制,使用printf “%x\n” tid命令进行转换
[root@tomcat02 message]# printf "%x\n" 24471
5f97
  1. 查看进程堆栈信息
[root@tomcat02 message]#jstack 24939 >>java.txt

在这里插入图片描述
查找状态为RUNNABLE,线程号为上一步计算后得到的5f97,找到此线程为GC线程,并没有找到想要的业务代码位置信息

查看dump文件(可跳过)

jmap -dump:format=b,file=heap.bin 24939
下载dump文件使用eclips进行分析
在这里插入图片描述
没有发现
说实话,并没有看懂,放弃!

监控堆栈信息

调用接口的时候反复监控堆栈信息

jstack 24939

图片是后边截取的,不是当时情况,仅供参考
在这里插入图片描述
发现每次调用都会执行一段redis代码,耗时较长,很是奇怪,打开代码自己看下

@Configuration
public class JedisClusterConfig {
    @Autowired
    private RedisProperties redisProperties;

    public JedisCluster getJedisCluster(){
        String [] serverArray=redisProperties.getClusterNodes().split(",");
        Set<HostAndPort> nodes=new HashSet<>();

        for (String ipPort:serverArray){
            String [] ipPortPair=ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));

        }
        String redisAuthPass = redisProperties.getRedisAuthPass();
        return  new JedisCluster(nodes,2000, 2000, 6, redisAuthPass, new JedisPoolConfig());
    }

}

发现每次调用redis都是重新初始化redis集群配置,问题大概出来了,正常redis初始化只需程序启动时执行一次,不必每次都执行,按此思路修改代码

@Configuration
public class JedisClusterConfig {
    @Autowired
    private RedisProperties redisProperties2;
    
    private static JedisCluster jedisCluster = null;
    
    private static RedisProperties redisProperties;
    
    @PostConstruct
    public void init() {
        redisProperties = redisProperties2;
        if (jedisCluster==null) {
            try {
                jedisCluster = reloadJedisCluster();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    private static JedisCluster reloadJedisCluster() throws Exception {
        System.out.println("初始化实体");
        JedisCluster cluster = null;
        String [] serverArray=redisProperties.getClusterNodes().split(",");
        Set<HostAndPort> nodes=new HashSet<>();

        for (String ipPort:serverArray){
            String [] ipPortPair=ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));

        }
        String redisAuthPass = redisProperties.getRedisAuthPass();
        cluster = new JedisCluster(nodes,2000, 2000, 6, redisAuthPass, new JedisPoolConfig());
        return cluster;
    }
    
    public JedisCluster getJedisCluster() throws Exception{
        if (jedisCluster == null) {
            synchronized (JedisClusterConfig.class) {
                jedisCluster = reloadJedisCluster();
            }
            return jedisCluster;
        } else {
            return jedisCluster;
        }
    }

}

再次部署后问题解决。

总结

如果是接口调用期间导致CPU暴涨,排除掉业务代码逻辑问题后,直接查看堆栈信息,从中找出可能存在问题的地方。
也可能是拦截器中问题导致。(本例)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值