首页 > 其他分享 >服务CUP飙高的问题排查

服务CUP飙高的问题排查

时间:2024-11-16 11:56:23浏览次数:1  
标签:排查 CUP List 更新 poReserveReceivingCapacityConfigs 飙高 query 操作 ReserveReceivingCap

1.问题描述

  • 7月4号,18:53分,值班时,WMS-SEVICE出现服务负载飙高的告警。

  • 自动生成的Dump

2.问题分析排查过程:

  • 看下"grafna"的服务监控,如下图,在18:50~18:55分这段时间内,确实服务CUP很高。

 为什么这么高啊?有大的网络IO操作吗?继续排查。

  • 分析jstack文件
  • 打开jstack文件,搜索"com.pupu",发现是截图所示的代码可能导致的这个问题

 疑问:看这个方法名是做更新操作的,为什么一个更新操作会导致服务CPU飙升啊?

  • 打开idea,找到上面截图中所示的代码处。OMG。。。这。。。

 

  •  他把这个更新操作放到了这个for循环中了。

这个updateCapacityConfig下面又有查询库操作

 List<ReserveReceivingCapacityConfig> reserveReceivingCapacityConfigs = reserveReceivingCapacityConfigMapper.selectList(query);

这个for循环中对象集合大小是89条,所以for循环会执行89次。

 

 

 而他把更新操作写在for代码里面,那意味着,每调用1次这个接口,他的更新方法会执行89次,而他的每个更新方法里面又有查询操作,那也就意味着这个查询操作也会执行89次。所以我们才看到会有很多查询对象产生(ReserveReceivingCapacityConfig)

下面是这个更新方法,这个更新方法有查询和更新操作

@Transactional(rollbackFor = Exception.class)
    public Integer updateCapacityConfig(List<ReserveReceivingCapacityConfigPO> pos) {
        if (CollectionUtils.isEmpty(pos)) {
            return 0;
        }
        List<ReserveReceivingCapacityConfig> poReserveReceivingCapacityConfigs = ConverterUtil.convert(pos, ReserveReceivingCapacityConfig.class);
        List<String> storeIds = poReserveReceivingCapacityConfigs.stream().map(ReserveReceivingCapacityConfig::getStoreId).distinct().collect(Collectors.toList());
        List<Integer> dates = poReserveReceivingCapacityConfigs.stream().map(ReserveReceivingCapacityConfig::getConfigDate).distinct().sorted().collect(Collectors.toList());

        LambdaQueryWrapper<ReserveReceivingCapacityConfig> query = Wrappers.lambdaQuery();
        query.eq(ReserveReceivingCapacityConfig :: getHasDeleted,false);
        query.in(ReserveReceivingCapacityConfig :: getStoreId,storeIds);
        query.between(ReserveReceivingCapacityConfig :: getConfigDate,dates.get(0),dates.get(dates.size() - 1));
        List<ReserveReceivingCapacityConfig> reserveReceivingCapacityConfigs = reserveReceivingCapacityConfigMapper.selectList(query);

        Iterator<ReserveReceivingCapacityConfig> iterator = poReserveReceivingCapacityConfigs.iterator();
        List<Long> removeIds = Lists.newArrayList();

        while (iterator.hasNext()) {
            ReserveReceivingCapacityConfig po = iterator.next();
            List<ReserveReceivingCapacityConfig> list = reserveReceivingCapacityConfigs.stream().filter(r -> r.getStoreId().equals(po.getStoreId()) &&
                    r.getConfigDate().equals(po.getConfigDate()) &&
                    r.getConfigHour().equals(po.getConfigHour()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)) {
                // 如果完全相同则不更新
                List<ReserveReceivingCapacityConfig> removes = list.stream().filter(r ->  r.getSkuCount().equals(po.getSkuCount()) && r.getProductCount().equals(po.getProductCount())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(removes)) {
                    iterator.remove();
                } else {
                    // 如果配置发生变化,则移除旧的保存新的
                    removeIds.addAll(list.stream().map(ReserveReceivingCapacityConfig::getId).distinct().collect(Collectors.toList()));
                }
            }
        }
        if (CollectionUtils.isNotEmpty(removeIds)) {
            log.warn("更新预约容量配置:removeIds = {}", JSONObject.toJSONString(removeIds));
            LambdaUpdateWrapper<ReserveReceivingCapacityConfig> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper
                    .in(ReserveReceivingCapacityConfig::getId, removeIds)
                    .set(ReserveReceivingCapacityConfig::getHasDeleted, true)
                    .set(ReserveReceivingCapacityConfig::getTimeUpdate,System.currentTimeMillis());
            reserveReceivingCapacityConfigMapper.update(updateWrapper);
        }
        if (CollectionUtils.isNotEmpty(poReserveReceivingCapacityConfigs)) {
            log.warn("更新预约容量配置:pos = {}", JSONObject.toJSONString(poReserveReceivingCapacityConfigs));
            return reserveReceivingCapacityConfigMapper.insertBatchSomeColumn(poReserveReceivingCapacityConfigs);
        }
        return 0;
    }

分析链路

  • 看下他的链路。Owl应用性能监控显示,他执行了很多次数据库操作

疑问:既然执行了很多次数据库操作,那数据库DB监控上应该会有所体现吧。

数据库DB监控

  • 看下数据库DB监控:证明这段时间“reservecapacityconfigs”这个表,确实有大量的数据库操作,其实这个对数据库也有很大的影响,并发量不大,如果并发量很高,数据库可能就直接gg了。

jmap文件

  • 再看看jmap文件:产生了很多新的对象(ReserveReceivingCapacityConfig),为什么会产生很多对象?

因为这个updateCapacityConfig下面又有查询库操作

 List<ReserveReceivingCapacityConfig> reserveReceivingCapacityConfigs = reserveReceivingCapacityConfigMapper.selectList(query);

他的每个更新方法里面又有查询操作,那也就意味着这个查询操作也会执行89次。所以我们才看到会有很多查询对象产生(ReserveReceivingCapacityConfig)。

问题定位

  • 所以:经过上面的这些排查,大概可以确定是这个update方法引起的。因为在for循环中执行了大量的数据库查询和更新操作,导致系统服务CPU飙升.这个更新接口耗时600s+.

调用入口

  • 定时任务定时执行的。刚上线,所以先手动执行了1次。

问题处理

  • 停掉该接口对应的定时任务

处理结果

  • 1.确认对业务没有影响,新建的表,新写的接口,业务还没有开始使用
  • 2.第二天,优化后发版上线
  • 3.生产问题复盘

标签:排查,CUP,List,更新,poReserveReceivingCapacityConfigs,飙高,query,操作,ReserveReceivingCap
From: https://www.cnblogs.com/lufei-123/p/18549235

相关文章

  • SurroundOcc_ Multi-Camera 3D Occupancy Prediction for Autonomous Driving
    SurroundOcc:Multi-Camera3DOccupancyPredictionforAutonomousDrivingZoteroAbstract3Dsceneunderstandingplaysavitalroleinvision-basedautonomousdriving.Whilemostexistingmethodsfocuson3Dobjectdetection,theyhavedifficultydescribin......
  • FlashOcc_ Fast and Memory-Efficient Occupancy Prediction via Channel-to-Height P
    FlashOcc:FastandMemory-EfficientOccupancyPredictionviaChannel-to-HeightPluginZoteroAbstractGiventhecapabilityofmitigatingthelong-taildeficienciesandintricate-shapedabsenceprevalentin3Dobjectdetection,occupancypredictionhasbec......
  • UltimateDO_ An Efficient Framework to Marry Occupancy Prediction with 3D Object
    UltimateDO:AnEfficientFrameworktoMarryOccupancyPredictionwith3DObjectDetectionviaChannel2heightZoteroAbstractOccupancyand3Dobjectdetectionarecharacterizedastwostandardtasksinmodernautonomousdrivingsystem.Inordertodeploy......
  • 对偶发接口频繁超时问题排查并解决
    问题排查现象       业务(重量级业务,比较庞大)高峰期接口偶尔频繁超时,重启机器即可恢复,或连续超时多次超时后pod内存溢出,直接触发重启后恢复。多次出现超时情况时jstack线程栈、jmap获取内存快照,对其进行分析后没明显异常。机器配置pod配置pod内存:5.1G(线上......
  • 网页直播/点播播放器EasyPlayer.js网页web无插件播放器渲染页面出现倒挂的原因排查
    EasyPlayer.js网页web无插件播放器属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,无须安装任何插件,起播快、延迟低、兼容性强,使用非常便捷。EasyPlayer.js播放器不仅支持H.264与H.265视频编码格式,也能支持WebSocket-FLV、HTTP-FLV、HLS(m3u8)、WebRTC、ws......
  • 宝塔面板安装网站后打不开的解决方法及排查步骤
    1.检查网络连接确认服务器网络是否正常:从服务器上尝试ping外部网站,确保网络畅通。例如:ping域名 或 ping你的网址2.检查宝塔面板状态登录服务器,检查面板是否正常运行:使用命令 bt 进入宝塔面板管理界面。如果面板未运行,尝试启动面板:btstart3.检查网站......
  • mysql batch insert 慢的问题排查过程
    1,发现线上的queue入库很慢因为我发现2024-11-1412:24:22.897[][Thread-47]INFO com.hp.nova.runner.Task3NewStructRedisQueueRunner.run[93]:eisrq.getType()======3...............2024-11-1412:25:57.653[][Thread-47]INFO com.hp.nova.runner.Task3NewSt......
  • Springboot毕业生就业服务平台cup0p(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表毕业生,企业,招聘信息,投递简历,在线咨询开题报告内容一、立题依据研究背景随着高等教育的普及和毕业生人数的不断增加,毕业生就业问题成为社会关注的焦点。然......
  • 题解:[XIX Open Cup, Grand Prix of Korea] Dev, Please Add This!
    前置知识:2-SAT题意[XIXOpenCup,GrandPrixofKorea]Dev,PleaseAddThis!在一张网格上有以下几种物品:空地(.)墙(#)星星(*)一个球(O)现在你要玩一个游戏。你可以让球朝上下左右某一个方向移动,但是一旦移动就必须走到底,也就是说直到前面是墙或者边界才能停。另外,如果你走......
  • 入侵排查之Linux
    目录1.黑客入侵后的利用思路2.入侵排查思路2.1.账号安全2.1.1.用户信息文件/etc/passwd2.1.2.影子文件/etc/shadow2.1.3.入侵排查2.1.3.1.排查当前系统登录信息2.1.4.2.查询可以远程登录的账号信息2.2.历史命令2.2.1.基本使用2.2.1.1.root历史命令2.2.1.2.打开/ho......