Java web应用性能分析之【CPU飙升分析概述】

64 篇文章 0 订阅

Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客

Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客

Java web应用性能分析概叙-CSDN博客

Java web应用性能分析之【基准测试】-CSDN博客

Java web应用性能分析之【sysbench基准测试】-CSDN博客

 CPU飙高的指标

        一般情况下,我们服务器的都比较空闲,因为cpu一般不是性能瓶颈。偶尔有进程的%cpu>100%,也是正常情况。毕竟是在多核cpu服务器上,进程里面起了多线程,%cpu>100%很正常。说明进程对CPU多核利用很充分。

        我们一般说cpu飙高,并不只是%CPU这一个参考值。上面“性能分析概叙”中有讲我们关注的点是下面这些,而且这些指标都是相互关联的,并不是某一项很高就说明有问题:

  •         cup利用率[us <70%,sy<35%,id>=95% ]
  •         cs每秒上下文切换次数,越小越好[cs<100];

                     cs和cpu利用率相关,如果能保持上面所说的利用率大量的切换可以接受

  •         %iowait <= 100/cpu核心 %,等待 io 的 cpu 时间占比,这个值将在磁盘监控中再讲。
  •         load avg运行队列/平均负载 [ load avg/cpu核心数 < 5]  (平均负载高有可能是cpu密集型任务)

        思考一个问题:%CPU低,Load avg>5,会出现这种情况吗,要命吗,是否要关注?

Java web应用性能分析之【思考一个问题:%CPU低,Load avg>5,会出现这种情况吗,要命吗,是否要关注?】-CSDN博客

        在我们Java Web应用运行环境中,各个服务和组件都是部署在不同的服务器上,一般按照部署情况分为不同的功能角色服务器:web服务器、应用服务器、文件服务器、数据库服务器、运维服务器。所以在不同服务器上,CPU飙升都对应着不同的场景、有着不同的原因、以及不同的解决方案。

        web服务器:运行Nginx、Apache、Tomcat等web服务器的服务器。主要功能是:路由、代理、负载均衡、跑前端工程。

        应用服务器:运行java应用的服务器。在springboot时代,应用服务器和web服务器还是要区分一下。

        文件服务器:提供文件存储、共享和管理的服务器。如图片服务器、合同文件、数据文件等。

        数据库服务器:运行数据库的服务器,如Oracle、MySQL、PG、Redis、KFK、ElasticSerch等等。

        运维服务器:主要是给运维管理用,如堡垒机、监控等。

CPU飙高需要关注和分析

        服务器的CPU占用率过高%CPU需要引起重视,而且要具体问题具体分析,然后再判断是否影响业务。因为CPU飙高可能会导致服务器运行缓慢、最终导致应用响应不及时,页面或者app卡顿,影响用户体验和业务。

CPU飙高原因

        一般导致CPU飙高的原因如下:

        1.硬件问题--CPU过热:因为风扇或者环境原因,导致CPU过热,可能会导致CPU性能下降,甚至出现系统死机或者操作系统重启。

       2.硬件老化:随着计算机使用时间的增长,硬件设备可能会出现老化问题。这可能会导致CPU的性能下降,从而影响计算机的整体性能。这个在移动通信行业很常见,一台运行了10年的服务器,没人敢重启,或者迁移;具体为什么,暂不说。

        3.恶意软件攻击:服务器被挂病毒,crontab中有杀不掉的进程,占用服务器资源,导致CPU飙升。服务器被DDOS攻击导致CPU飙高。

        4.应用缺陷:以java应用为例。

1、无限循环或死循环:程序中存在错误的循环结构,导致程序一直在循环执行,从而消耗大量的CPU资源。

2、复杂的算法和计算:程序中执行复杂的算法、大规模的数据处理或者需要大量计算的操作可能导致CPU占用过高。

3、频繁的IO操作:如果程序频繁地进行文件读写、网络通信等IO操作,可能会导致CPU占用增加。

4、线程问题:多线程程序中,线程可能因为竞争条件、死锁、阻塞等问题导致CPU占用过高。

5、CAS自选一直充实导致CPU飙高、没有控制次数。

6、不合理的线程池配置:如核心线程数和最大线程数一样,都比较大,导致一些空闲的线程得不到回收;凭空多了很多无意义的消耗。

7、内存问题:内存泄漏或内存占用过高可能导致Java虚拟机频繁进行垃圾回收,从而增加CPU负担。

8、不合理的资源管理:没有正确释放或管理资源,如打开的文件、数据库连接等,可能导致CPU占用过高。

9、第三方库或框架问题:使用的第三方库、框架或组件可能存在性能问题,导致程序CPU占用增加。

10、并发问题:不正确的并发控制或同步机制可能导致竞争条件和性能问题。

11、缓存问题:缓存未有效利用,导致程序频繁地从内存或磁盘读取数据,增加了CPU负担。

12、频繁的异常处理:频繁的异常处理可能会导致CPU占用过高,因为异常处理可能会涉及昂贵的堆栈跟踪等操作。

       

        5.应用利用多核CPU进行并行业务处理:一般是正常现象,只要不是长时间占用都是正常现象。

        6.应用运行过多:单台服务器上启动的进程太多了。一般常见于我们的测试环境、测试或者开发都想跑一下他们的场景,启动的应用进程太多。

        7.web服务器繁忙:以Nginx为例,在高并发、高访问量的web服务场景,需要启动更多的nginx进程来快速处理响应大并发量的用户请求。

        8.数据库进程:mysql进程飙高。原因很多:慢sql 和全表扫描导致的大量的iowait等待引起cpu飙高、数据库锁(行锁冲突、锁等待、锁超时、死锁等)、mysql参数设置不合理等等,可能的原因较多,需要层层递进,逐步定位根因;

        9.数据库进程:oracle进程飙高。原因很多:排序、SQL解析、执行计划突变、全表扫描、会话阻塞等都会导致CPU飙升,可能的原因较多,需要层层递进,逐步定位根因;

        10.数据库进程:redis进程飙高。

原因很多:
1.redis漏洞导致服务器被注入挖矿脚本。

2.命令频繁执行:当 Redis 服务器接收到大量的命令并且频繁执行时,会导致 CPU 使用率飙升。这可能是因为某个应用程序在短时间内发送了大量的读写请求,导致 Redis 无法及时处理这些请求。

3.大数据集操作:当操作一个非常大的 Redis 数据集时,例如进行排序、聚合等操作,会占用大量的 CPU 资源,导致 CPU 使用率升高。

4.慢查询:Redis 是单线程的,当执行一个复杂查询或者一个很长时间的操作时,会阻塞其他命令的执行,导致整个 Redis 服务器的 CPU 使用率上升。或者是执行了keys*等消耗资源的命令,排查及处理措施请参考查找并禁用高消耗命令。高消耗资源的命令即时间复杂度为O(N)或更高的命令,通常情况下,命令时间复杂度越高,在执行时消耗的资源越高,这会导致CPU使用率超高,容易触发主备倒换。关于各命令对应的时间复杂度信息请参见Redis官网。例如,使用了keys等消耗资源的命令,导致CPU超高,建议客户改成scan命令或者禁用keys命令。

5.内存交换:当 Redis 内存使用超过物理内存限制,操作系统会将部分 Redis 进程内存交换到磁盘上,导致 CPU 使用率升高。

6.高并发访问:当有大量的并发连接访问 Redis 服务器时,会导致 CPU 使用率飙升。客户的业务负载过重,qps过高,导致CPU被用满,排查方法请参考排查QPS是否过高。此时可以查看Info指令下的commandstats子指令进行分析和输出。分析指令执行情况。

7.内部线程过于繁忙:当 Redis 内部线程过于繁忙时,可能导致 CPU 占用过高。Redis 内部线程包括后台线程和网络线程,后台线程用于执行一些周期性任务,如过期键的删除和AOF日志的写入,而网络线程用于处理客户端请求和网络I/O。当后台或网络线程被阻塞或者执行任务耗时过长时,可能导致线程池中的线程不足,从而导致占用过高的情况。

8. Redis 主从同步延迟:当 Redis 主从同步延迟过高时,可能导致 CPU 占用过高。因为主从同步过程中,从节点需要进行一些耗时的操作,如从主节点复制数据、AOF日志同步以及数据重放等。当同步延迟过高时,可能会导致从节点处于不稳定状态,从而导致占用过高的情况。

9. Redis 持久化操作耗时过长:当使用 Redis 持久化机制时,在执行RDB或AOF操作时,可能会导致 CPU 占用过高。因为RDB和AOF操作都是需要对内存中的数据进行序列化和写入磁盘的操作,这些操作可能会耗费大量的 CPU和I/O资源,从而导致占用过高的情况。

10. Redis 数据库编码错误:当 Redis 使用了不正确的编码方式时,可能会导致 CPU 占用过高。在 Redis 中,每种数据类型都有对应的编码方式,如字符串可以使用int、raw、embstr三种编码方式。当使用错误的编码方式时,可能会导致内存中的数据结构变得复杂,从而导致占用过高的情况。

        11.数据库进程:kfk进程飙高

        12.数据库进程:ElasticSearch进程飙高

CPU飙高解决措施

        解决CPU占用过高问题可能需要详细的分析和调试,特别是在复杂的应用程序中。如果问题仍然存在,就需要专业的开发人员的帮助。

        1.升级硬件设备:如果计算机使用时间较长,可以考虑升级硬件设备,例如更换更快的CPU、增加内存等。

        2.定期清理散热器和风扇:如果计算机使用时间较长或者经常出现高温问题,可以定期清理散热器和风扇,以保证计算机的正常散热和降温。

        3.恶意攻击:安全加固、漏洞扫描、防火墙上配置合理的安全访问规则、Nginx限流。

        4.应用软件缺陷:以java为例

                将在下一篇详细说明。

        5.应用利用多核CPU进行并行业务处理:一般是正常现象,只要不是长时间占用都是正常现象。

        6.应用运行过多:操作规范、服务器上定期检查、关闭不必要的进程。

        7.web服务器繁忙:以Nginx为例,在高并发、高访问量的web服务场景,需要启动更多的nginx进程来快速处理响应大并发量的用户请求。

Java web应用性能分析服务端慢之Nginx慢-CSDN博客

        参考上面文章,去优化和调整Nginx,包括:优化worker进程、worker绑定cpu、调整单个进程运行最大连接数worker_connections、高校文件传输模式(sendfile、tcp_nopush两个参数)、连接超时等。

        8.数据库进程:mysql进程飙高。原因很多:慢sql 和全表扫描导致的大量的iowait等待引起cpu飙高、数据库锁(行锁冲突、锁等待、锁超时、死锁等)、mysql参数设置不合理等等,可能的原因较多,需要层层递进,逐步定位根因;

Java web应用性能分析之【MySQL安装注意事项】-CSDN博客

Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客

        参考这两篇文章去调整mysql参数和定位sql问题,然后验证。

        9.数据库进程:oracle进程飙高。原因很多:排序、SQL解析、执行计划突变、全表扫描、会话阻塞等都会导致CPU飙升,可能的原因较多,需要层层递进,逐步定位根因;

一、分析方法包括哪些:
    主要由主机top/topas占CPU高的进程查询相应SQL、会话增长趋势、阻塞分析、ASH/AWR报告分析、SQL执行时间/执行计划变化等;了解业务场景,业务上有没有变更,例如开发功能变更、业务使用量增加等。
    在很多应用场景中,数据库的稳定性直接决定了系统的稳定性。本文介绍一些通用的数据库问题处理技巧,健壮的数据库不能解决所有的问题,但是却能增加数据库运行的稳定性。
二、分析说明
    通过分析日志定位、分析故障原因;追溯历史数据,分析关键指标的历史波动,这些关键指标可以用来做为数据库健康度参考指标。
    用实际数据来验证推断,排除掉其它干扰因素,定位数据库问题的根本原因,帮助快速修复。
三、疑问点排查及分析思路
1、主机top信息
    可以通过top命令看一下单一进程使用CPU的情况,有CPU使用高的可以通过pid定位sid最终定位sql_id。
    本次通过主机top信息看到进程使用CPU都很平均,无法直接定位是某个进程某个SQL引起的CPU使用过高的问题。
2、查询CPU top10的语句
set linesize 200
col username for a15
co1 event for a35
col program for a28
col cpu_p for 99.99
select ta.,round(ta.cpu_time / tb.total_cpu * 100,1) cpu_usage
  from(
     select s.username,
            s.program,
            s.event,
            s.sql_id,
             sum(trunc(m.cpu))cpu_time,
            count()sum
      from v$sessmetric m,v$session s
      where(m.physical_reads >100 or m.cpu >180 or
            m.logical_reads >180)
        and m.session_id = s.sid
        and m.session_serial_num = s.serial#
        and s.status ='ACTIVE'
        and username is not null
      group by s.username,s.program,s.event,s.sql_id
      order by 5 desc)ta,
    (select sum(cpu) total_cpu from v$sessmetric)tb
where rownum<11;

结合AWR信息:
    可以看到,故障时段,853by1q5drtc2语句占用最大的CPU时间和逻辑读,接下去就是怎么优化这个SQL的问题。
2、sql信息
    执行计划:
    历史执行计划:
可以看到执行计划产生了不合理的变化,执行时间差异很大,这是CPU占用过大的根本原因。
3、执行计划为什么会改变?
表统计信息失效了?
select owner.
table_name,
partition_name,
object_type,
stale_stats,
last_analyzed
from dba_tab_statistics
where table_name = upper('&table_name');

表统计信息确实失效了。
    ORACLE是根据数据改变量大于10%才进行统计信息的收集,且对静态表并不收集统计信息。至此,CPU使用率高的问题得到了最终解决,最终是由于统计信息没有正确收集导致的,
定位了问题,解决就很容易了,更新表统计信息后执行sql看一下效率及执行计划都恢复正常。本次是表统计失效导致的执行计划改变,如果不是因为统计信息失效导致的,可以采用的优化方案包括不限于修改SQL、指定HINT的方式修正执行计划,实在无法修改SQL的再使用SPM或SQLPROFILE进行绑定等。
4、关于统计信息收集
    1)当系统有很大的分区表时,如果总是全部收集则会比较慢,11g之后可以设置INCREMENTAL只对数据有变动的分区做收集,如下示:
exec dbms_stats.set_table_prefs('JD','IMS_RES_MONITOR_2','INCREMENTAL','TRUE');
exec dbms_stats.set_table_prefs(user,'table_name','INCREMENTAL','TRUE'); --只            收集数据变动的分区
select dbms_stats.get_prefs('INCREMENTAL',null,'table_name') from dual;  --只看分区表INCREMENTAL的值
2)延长自动统计信息收集时间
    自动收集统计信息的时间是周一到周五每晚22:00:00到第二天2:00结束,周六周日两天全天收集。可进一步考虑工作日时段延长2小时,即周一到周五时段统计信息收集到第二天4:00结束。

        10.数据库进程:redis进程飙高。

也可以参考:

       Redis CPU使用率高的原因排查和解决方法_云数据库 Redis 版(Redis)-阿里云帮助中心

原因很多:
1.redis漏洞导致服务器被注入挖矿脚本。
    解决方案:
    1.清除crontab中注入的脚本:先注释crontab,再删除crontab中对应的脚本,然后删除crontab,最后杀掉进程。
    2.修改默认端口6379.
    3.bind内网ip,只允许内网访问
    4.设置复杂度高的redis密码

2.命令频繁执行:当 Redis 服务器接收到大量的命令并且频繁执行时,会导致 CPU 使用率飙升。这可能是因为某个应用程序在短时间内发送了大量的读写请求,导致 Redis 无法及时处理这些请求。
    解决方案:
    1.使用管道(pipeline)批量发送命令:将多个命令打包成一个请求发送给 Redis,减少网络开销和服务器负载。
    2.使用 Redis 事务(transaction)操作:将多个命令包装在 MULTI 和 EXEC 之间,保证这些命令是原子执行的。下面是使用 Python Redis 库进行事务操作的示例代码:

3.大数据集操作:当操作一个非常大的 Redis 数据集时,例如进行排序、聚合等操作,会占用大量的 CPU 资源,导致 CPU 使用率升高。
    解决方案:
    1.使用分布式缓存:将大数据集分散到多个 Redis 实例上,减轻单个服务器的负载压力。

4.慢查询:Redis 是单线程的,当执行一个复杂查询或者一个很长时间的操作时,会阻塞其他命令的执行,导致整个 Redis 服务器的 CPU 使用率上升。或者是执行了keys*等消耗资源的命令,排查及处理措施请参考查找并禁用高消耗命令。高消耗资源的命令即时间复杂度为O(N)或更高的命令,通常情况下,命令时间复杂度越高,在执行时消耗的资源越高,这会导致CPU使用率超高,容易触发主备倒换。关于各命令对应的时间复杂度信息请参见Redis官网。例如,使用了keys等消耗资源的命令,导致CPU超高,建议客户改成scan命令或者禁用keys命令。
    解决方案:
    1.优化查询:避免执行复杂的查询,尽量使用 Redis 提供的高效查询方式。
    2.使用异步操作:将一些长时间运行的操作转换为异步执行,避免阻塞其他命令的执行。
    3.拆分大key
    4.禁用大消耗命令:

5.内存交换:当 Redis 内存使用超过物理内存限制,操作系统会将部分 Redis 进程内存交换到磁盘上,导致 CPU 使用率升高。
    解决方法:
    1.监控 Redis 内存使用情况,避免超过物理内存限制。
    2.调整操作系统的内存交换策略,避免频繁的内存交换。

6.高并发访问:当有大量的并发连接访问 Redis 服务器时,会导致 CPU 使用率飙升。客户的业务负载过重,qps过高,导致CPU被用满,排查方法请参考排查QPS是否过高。此时可以查看Info指令下的commandstats子指令进行分析和输出。分析指令执行情况。
    解决方法:
    1.配置 Redis 的最大连接数(maxclients)参数,限制并发连接的数量。
    2.使用连接池管理连接,避免频繁地建立和关闭连接。

7.内部线程过于繁忙:当 Redis 内部线程过于繁忙时,可能导致 CPU 占用过高。Redis 内部线程包括后台线程和网络线程,后台线程用于执行一些周期性任务,如过期键的删除和AOF日志的写入,而网络线程用于处理客户端请求和网络I/O。当后台或网络线程被阻塞或者执行任务耗时过长时,可能导致线程池中的线程不足,从而导致占用过高的情况。
8. Redis 主从同步延迟:当 Redis 主从同步延迟过高时,可能导致 CPU 占用过高。因为主从同步过程中,从节点需要进行一些耗时的操作,如从主节点复制数据、AOF日志同步以及数据重放等。当同步延迟过高时,可能会导致从节点处于不稳定状态,从而导致占用过高的情况。
9. Redis 持久化操作耗时过长:当使用 Redis 持久化机制时,在执行RDB或AOF操作时,可能会导致 CPU 占用过高。因为RDB和AOF操作都是需要对内存中的数据进行序列化和写入磁盘的操作,这些操作可能会耗费大量的 CPU和I/O资源,从而导致占用过高的情况。

    789解决方案:
    1. 使用 Redis 的性能分析工具
    Redis 自身提供了一些性能分析工具,如redis-cli、redis-benchmark和redis-slowlog等,它们可以帮助我们对 Redis 进行深入的性能分析和诊断。通过对这些工具的使用,我们可以获得 Redis 的运行状态、命令执行时间、耗时操作慢日志等信息,从而更好地定位 Redis CPU 占用过高的原因。
    2. 优化 Redis 的配置文件
    Redis 的配置文件(redis.conf)可以对 Redis 的运行参数进行调整,从而优化 Redis 的性能和稳定性。在遇到 Redis CPU 占用过高的问题时,我们可以通过调整 Redis 的配置文件的参数,如最大内存限制、线程池大小、RDB和AOF持久化等,来优化 Redis 的性能和确保其稳定性。
    3. 排查网络和磁盘I/O问题
    Redis 运行时需要进行网络和磁盘I/O访问,当网络和磁盘I/O存在问题时,也可能导致 CPU 占用过高。因此,在排查 Redis CPU 占用过高时,我们也需要对网络和磁盘I/O进行排查,查看是否存在网络延迟、磁盘I/O负载过高等问题。


10. Redis 数据库编码错误:当 Redis 使用了不正确的编码方式时,可能会导致 CPU 占用过高。在 Redis 中,每种数据类型都有对应的编码方式,如字符串可以使用int、raw、embstr三种编码方式。当使用错误的编码方式时,可能会导致内存中的数据结构变得复杂,从而导致占用过高的情况。
    解决方案:检查 Redis 数据库编码。在使用 Redis 时,我们需要注意选择正确的数据类型和编码方式,以免出现占用过高的情况。如果存在编码错误,我们需要对 Redis 数据库进行相应的调整,从而优化 Redis 的性能和稳定性。

        redis问题排查

Redis CPU占用过高会导致所有使用Redis的客户端性能大幅下降,可能的原因中其中一个是大量的请求,尤其是keys命令请求过多,查询流程:

1. 使用info和monitor命令(这两个命令也可以登录之后使用,不过有可能造成client的crash)

redis-cli -h 192.168.1.*  -a 'xxx' info 

redis-cli -h 192.168.1.*  -a 'xxx' monitor 

info命令会显示当前的状态,monitor会显示当前的客户端的命令请求;

2. 使用慢查询 

redis-cli -h 192.168.1.*  -a 'xxx' slowlog get (reset替换get清空旧的log)

        11.数据库进程:kfk进程飙高

                待补充

        12.数据库进程:ElasticSearch进程飙高

                待补充

  • 40
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Java程序中,可能会出现CPU飙升的情况,导致CPU占用率异常高。这种情况通常是由于程序中存在某些问题导致的,以下是几个可能引起CPU飙升的原因和解决方法: 1. 无限循环:如果程序中存在无限循环或者循环次数过多的情况,会导致CPU不断处理循环,造成占用率飙升。解决方法是检查代码中的循环逻辑,确保循环条件正确,并添加合适的退出机制。 2. 频繁的IO操作:如果程序中存在大量的IO操作,特别是磁盘读写或网络通信,会消耗大量的CPU资源,导致占用率飙升。解决方法是对IO操作进行优化,如使用缓冲区、批量处理等方式减少IO次数。 3. 线程处理不当:如果程序中使用了大量的线程,而这些线程没有得到合理的调度和管理,会导致CPU负载过高。解决方法是检查线程逻辑,确保线程的启动和销毁得当,并考虑使用线程池等方式管理线程。 4. 死锁或竞态条件:如果程序中存在死锁或竞态条件,会导致多个线程互相等待对方释放资源,从而造成CPU飙升。解决方法是对代码进行仔细审查,确保没有死锁或竞态条件的存在。 5. 过度使用递归:如果程序中过度使用递归算法,会导致CPU进行大量的方法调用,从而造成占用率飙升。解决方法是使用迭代或其他非递归方式实现算法,避免过深的递归调用。 总之,当Java程序引起CPU飙升时,需要仔细检查代码逻辑,并对可能的问题进行排查和优化,以确保程序的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-无-为-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值