CPU飙升排查思路

在对接E签宝的CA认证过程中,由于在调用服务时使用log.info()打印大量日志,尤其是在进行压力测试时,发现CPU使用率急剧升高并导致响应时间延长。通过top命令定位到异常进程和线程,使用jstack分析发现日志记录方法(如logger.info)是同步的,导致线程阻塞在callAppenders()方法上。问题在于大量日志输出造成的同步瓶颈。
摘要由CSDN通过智能技术生成

最近公司有个需求是对接E签宝的,也就是CA认证,大致的情况就是我们拿着文件去E签宝做CA认定,简单的理解就是拿着合同去E签宝盖章。
因为是对接三方的吗,所以在调E签宝服务的时候我就用log.info()把请求参数给打印了出来,方便看组装的参加,排查问题,参数中就包含我们的合同文件流,所以整个参数是一个大对象。在做压测的时候发现CPU很快就飙升到100%,并且耗时很久。但是我把打印日志的log.info()去掉之后,CPU和耗时马上就降下来了。下面开始排查这个问题:

首先使用top命令查看进程运行情况:

# top
  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 7020 root      20   0 2538892 164144  11856 S  90.3  8.7  61:23.54 java
11022 root      20   0 2560528 241340  11920 S  0.3 12.8 311:23.23 java
26805 root      20   0   32612   4036   2472 S  0.3  0.2  24:50.95 AliYunDunUpdate
26838 root      10 -10  134120  14524   5924 S  0.3  0.8 343:05.22 AliYunDun
    1 root      20   0   43280   3300   2108 S  0.0  0.2   2:16.82 systemd
    2 root      20   0       0      0      0 S  0.0  0.0   0:01.78 kthreadd
    3 root      20   0       0      0      0 S  0.0  0.0   1:30.68 ksoftirqd/0
    5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
    7 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0
    8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh                 
    9 root      20   0       0      0      0 S  0.0  0.0  65:15.85 rcu_sched             
   10 root      rt   0       0      0      0 S  0.0  0.0   2:14.65 watchdog/0             
   12 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kdevtmpfs             
   13 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 netns                 
   14 root      20   0       0      0      0 S  0.0  0.0   0:00.00 khungtaskd             
   15 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 writeback             
   16 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kintegrityd

查询到7020这个进程有异常,在继续查看具体异常线程。

# top -Hp 7020
 PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 23328 root      20   0 2538892 164144  11856 S  90.0  8.7   0:00.00 java

找到了当前异常进程下的异常线程后使用jstack查看详细情况

# jstack -l 6377 > error.log

将线程ID打印成16进制形式
# printf "%x\n" 23328
5b20

然后从jstack里查询该线程信息

# grep '18e9' error.log --color
"http-bio-6379-exec-200" #8869954 daemon prio=5 os_prio=0 tid=0x00007f74a81f6800 nid=0x5b20 waiting for monitor entry [0x00007f742457f000]

最后从jstack文件定位到堆栈信息

"http-bio-7020-exec-200" #8869954 daemon prio=5 os_prio=0 tid=0x00007f74a81f6800 nid=0x5b20 waiting for monitor entry [0x00007f742457f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.apache.log4j.Category.callAppenders(Category.java:204)
	- waiting to lock <0x00000000800371d0> (a org.apache.log4j.spi.RootLogger)
	at org.apache.log4j.Category.forcedLog(Category.java:391)
	at org.apache.log4j.Category.log(Category.java:856)
	at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:368)

结论

在log4j 中,logger.info等日志记录方法是同步的(使用了synchronized),大量的日志导致线程阻塞在callAppenders()这个方法,也就是这个地方导致压测阻塞,响应耗时比较久的问题。

public void callAppenders(LoggingEvent event) {
        int writes = 0;

        for(Category c = this; c != null; c = c.parent) {
            synchronized(c) {
                if (c.aai != null) {
                    writes += c.aai.appendLoopOnAppenders(event);
                }

                if (!c.additive) {
                    break;
                }
            }
        }

        if (writes == 0) {
            this.repository.emitNoAppenderWarning(this);
        }

    }
当 docker 上的服务出现 CPU 飙升的情况时,可以按照以下步骤进行排查: 1. 查看容器的 CPU 使用情况 可以使用 `docker stats <container_name>` 命令查看容器的 CPU 使用情况,可以根据容器的 CPU 使用情况来判断是否是容器内部的问题导致的 CPU 飙升。 2. 查看容器内部的进程占用情况 进入容器内部,使用 `top` 命令查看进程占用情况,可以看到哪个进程占用了大量的 CPU 资源。如果是某个进程占用了大量的 CPU 资源,可以考虑优化这个进程的代码,或者增加资源限制。 3. 检查容器的资源限制 检查容器的资源限制,包括 CPU 和内存限制。如果容器没有设置 CPU 限制,可能会导致容器内部的进程占用了大量的 CPU 资源,导致 CPU 飙升。可以通过 `docker update --cpus <cpus>` 命令来设置容器的 CPU 限制。 4. 检查宿主机的资源使用情况 如果容器内部的 CPU 使用情况正常,可以考虑检查宿主机的资源使用情况。如果宿主机的 CPU 使用率已经很高,容器就有可能无法获取到足够的 CPU 资源,导致 CPU 飙升。可以使用 `top` 命令查看宿主机的 CPU 使用情况。 5. 检查容器的日志 如果以上方法都无法解决问题,可以考虑查看容器的日志,查找是否有异常信息。可以使用 `docker logs <container_name>` 命令查看容器的日志。 总之,排查 docker 上的服务 CPU 飙升问题需要综合考虑多种因素,包括容器内部进程占用情况、容器的资源限制、宿主机的资源使用情况和容器的日志等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值