记一次cpu暴增的问题处理

问题表现

设备控制提示超时失败

问题排查

第一次排查

  1. 查看连接服务日志,发现日志提示内存溢出
  2. dump连接服务堆内存,发现是线程池导致的内存溢出(看代码分析发现是没有限制线程池的大小,然后程序处理也比较慢,导致线程池无限增大导致的)
  3. top命令查看cpu占用发现cpu占用达到了平均140%

第一次优化

  1. 看代码发现UDP接收处理的工作线程只有一个线程在处理,然后处理的线程池无限增大后,处理不过来,导致设备回复的ACK没有及时处理
  2. 通过修改线程池限制,增加UDP处理线程,拆分数据处理部分,数据处理延后,UDP通讯保证及时性

优化结果

  1. 优化完成后cpu占用率降低到平均60%左右
  2. 优化后jvm内存回收还是比较快,年轻代增长过快,导致内存很快会进入老年代(分析后认为还是有性能瓶颈,导致每次请求生成的对象占用堆内存过久,导致很快就进入老年代)

第二次排查

  1. 第一次优化过后,虽然cpu使用率降下来了一些,但还是比较高,后面使用top -Hp pid命令查看java进程的各线程cpu占用,发现是数据处理比较慢
  2. 在测试环境通过visualvm抓取线程cpu使用时间分析,发现是执行js公式时间过长

第二次优化

  1. 分析发现是每次都会去创建新的ScriptEngine对象然后直接执行公式
  2. 修改公式执行方法,添加预编译公式执行
public class ScriptEngineUtils {

    private static ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("JavaScript");

    private static Map<String, CompiledScript> COMPILED_SCRIPT_MAP = new ConcurrentHashMap<>(10);

    public static CompiledScript getCompiledScript(String script) {
        return COMPILED_SCRIPT_MAP.computeIfAbsent(script, s -> {
            try {
                return ((Compilable) SCRIPT_ENGINE).compile(s);
            } catch (ScriptException e) {
                throw new RuntimeException("创建编译脚本失败", e);
            }
        });
    }

    public static Bindings createBindings() {
        return SCRIPT_ENGINE.createBindings();
    }

    public static Object execute(CompiledScript compiledScript, Bindings bindings) throws ScriptException {
        return compiledScript.eval(bindings);
    }
}

优化结果

  1. cpu占用直接降到10%左右,老年代内存也不在快速增加

优化总结

代码整体存在一下几个问题

  1. 线程池没有限制直接使用的ScheduledThreadPoolExecutor没有限制最大线程数,排队线程数也没有限制,使用线程池时,一定要限制最大线程数和排队线程方法
  2. netty udp连接处理默认只有一个工作线程,接收到消息之后没有新开线程处理,导致消息堆积,需要在接收到消息之后新开线程进行处理,也可以开启netty的端口多路复用来提升性能
  3. java执行js脚本性能会比较差,每次调用都会使用反射创建新的处理类进行脚本执行,这里需要用到缓存预编译的形式来提升处理速度
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值