欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux线上CPU占用过高排查

程序员文章站 2024-01-23 12:16:46
...

问题是这样的,将项目部署到服务器上后,发现应用程序的响应速度非常慢,于是开始进行了排查。

TOP
首先查看系统资源占用信息,TOP看一下

Linux线上CPU占用过高排查

发现正在运行的JAVA项目CPU占用率很高,百分之110左右了,那么问题一定出在这个程序中

Ps -mp pid -o THREAD,tid,time
再通过ps命令查看这个程序的线程信息,tid代码线程ID,time代表这个线程的已运行时间

Linux线上CPU占用过高排查

由上面TOP可知进程ID为17569

于是可以看到这个进程中有3个线程的CPU占用率很高,并且它们目前也运行了13分钟了,它们的TID分别为17569

进制转换,2HEX
再将这3个TID转为16进制,为等会在jstack中查找方便
Printf “%x\n” number

Linux线上CPU占用过高排查
得到这个数的16进制为44a1

jstack查看进程信息
有了线程ID的16进制后,再在jstack中查看进程堆栈信息(之所有拿到TID信息,主要是为了查找方便)
通过jstack -pid 再grep查询

Linux线上CPU占用过高排查
从这里能看出,这3个线程目前还处于运行状态的
再通过jstack查看详细点的信息

Linux线上CPU占用过高排查

Linux线上CPU占用过高排查

Linux线上CPU占用过高排查
其中显示出了较为详细的代码信息
本地代码问题排查
再通过回到代码中查看CanalLauncher.main方法

Linux线上CPU占用过高排查

 通过code review发现,canal的代码中有一段连接判断的while循环,一直在调用,修改增加Thread.sleep(),问题解决

public static void main(String[] args) {
        try {
            running = true;
            logger.info("## set default uncaught exception handler");
            setGlobalUncaughtExceptionHandler();

            logger.info("## load canal configurations");
            String conf = System.getProperty("canal.conf", "classpath:canal.properties");
            Properties properties = new Properties();
            RemoteConfigLoader remoteConfigLoader = null;
            if (conf.startsWith(CLASSPATH_URL_PREFIX)) {
                conf = StringUtils.substringAfter(conf, CLASSPATH_URL_PREFIX);
                properties.load(CanalLauncher.class.getClassLoader().getResourceAsStream(conf));
            } else {
                properties.load(new FileInputStream(conf));
            }

            remoteConfigLoader = RemoteConfigLoaderFactory.getRemoteConfigLoader(properties);
            if (remoteConfigLoader != null) {
                // 加载远程canal.properties
                Properties remoteConfig = remoteConfigLoader.loadRemoteConfig();
                // 加载remote instance配置
                remoteConfigLoader.loadRemoteInstanceConfigs();
                if (remoteConfig != null) {
                    properties = remoteConfig;
                } else {
                    remoteConfigLoader = null;
                }
            }

            final CanalStater canalStater = new CanalStater();
            canalStater.start(properties);

            if (remoteConfigLoader != null) {
                remoteConfigLoader.startMonitor(new RemoteCanalConfigMonitor() {

                    @Override
                    public void onChange(Properties properties) {
                        try {
                            // 远程配置canal.properties修改重新加载整个应用
                            canalStater.destroy();
                            canalStater.start(properties);
                        } catch (Throwable throwable) {
                            logger.error(throwable.getMessage(), throwable);
                        }
                    }
                });
            }

            while (running) {
                Thread.sleep(1000);
            }

            if (remoteConfigLoader != null) {
                remoteConfigLoader.destroy();
            }
        } catch (Throwable e) {
            logger.error("## Something goes wrong when starting up the canal Server:", e);
        }
    }

重新打包mvn clean install -Dmaven.test.skip -Denv=release,上传替换问题解决。

读者看到这里,基本上猜出个大概,是的就是阿里的mysql跨机房数据同步中间件canal