首页 > 编程语言 >不扒瞎,这个程序让我从300s优化到了10s

不扒瞎,这个程序让我从300s优化到了10s

时间:2022-09-30 12:11:43浏览次数:55  
标签:commonRequestDTO om null CommonRequestDTO 300s new 10s 序列化 优化

前天晚上加班完成部门Q4KPI考核计划后,看到业务开发组的几个小伙伴在处理生产问题。我上前了解情况。

 

销管系统,客户交易明细页面,查询客户交易数据的逻辑是:调用远程数据中心接口,拿到原始交易数据集合,然后在内存里通过相关id来给客户名称、服务商名称、销售人员名称、所属部门、上级销售主管赋值。

 

 

产品经理反馈,销售主管登陆系统查询数据时,非常慢,慢到4~5分钟。

查看日志,发现后台程序处理耗时动辄高达300s。

300s是个庞大的数字!当务之急,是看能不能降低到10s以内。通过分析,其中,获取远程交易数据耗时≈6s,本地内存数据匹配竟然耗时200多秒,incredible!unbelievable!

 

 

那接下来要对各个匹配数据的程序段来分析。通过细化耗时,发现在for循环匹配销售数据为销售人员名称、所属部门、上级销售主管赋值时,异常地慢。

贴出来这段代码:

/**  * 查询销售与部门的关联关系  * @param saleId  * @return  */ public CommonRequestDTO selectSaleDepartRelation(Integer saleId){     List<CommonRequestDTO> relationList = CacheUtil.getCache(SaleCommonConstant.SALE_DEPART_RELATION, SaleCommonConstant.EXPIRY_SECONDS, ()             -> emaxSalerMapper.selectSaleDepartRelation()     );     relationList = relationList.stream().filter(o -> saleId.equals(o.getSaleId())).collect(Collectors.toList());     if(CollectionUtils.isNotEmpty(relationList)){         CommonRequestDTO commonRequestDTO = relationList.get(0);         commonRequestDTO.setSaleName(commonRequestDTO.getSaleName());         commonRequestDTO.setDepartName(commonRequestDTO.getDepartName());         commonRequestDTO.setDepartHeaderName(commonRequestDTO.getDepartHeaderName());         return commonRequestDTO;     }     return null; }

其中,CacheUtil封装了Redis的get/set操作。
emaxSalerMapper#selectSaleDepartRelation是查数据库获取基础关系数据,共223条数据,耗时6~7ms。
CommonRequestDTO是一个pojo模型类。

 

那么,这段代码也看不出哪里慢呀!

 

仔细一分析,发现端倪。Cc同学怀疑问题出在读redis上。果不其然,for循环里频繁调用redis获取集合数据,尤其是当查询数据记录多循环次数多时,必然拉跨。
当务之急,最好的解决办法,是用本地缓存来搞,HutoolCache登场。

static TimedCache<String ,List<CommonRequestDTO>> cache= cn.hutool.cache.CacheUtil.newTimedCache(SaleCommonConstant.EXPIRY_SECONDS);   /**  * 查询销售与部门的关联关系  * @param saleId  * @return  */ public CommonRequestDTO selectSaleDepartRelation(Integer saleId){     if (cache.get(SaleCommonConstant.SALE_DEPART_RELATION)==null){         cache.put(SaleCommonConstant.SALE_DEPART_RELATION, emaxSalerMapper.selectSaleDepartRelation());     }       List<CommonRequestDTO> relationList = cache.get(SaleCommonConstant.SALE_DEPART_RELATION);     relationList = relationList.stream().filter(o -> saleId.equals(o.getSaleId())).collect(Collectors.toList());     if(CollectionUtils.isNotEmpty(relationList)){         CommonRequestDTO commonRequestDTO = relationList.get(0);         commonRequestDTO.setSaleName(commonRequestDTO.getSaleName());         commonRequestDTO.setDepartName(commonRequestDTO.getDepartName());         commonRequestDTO.setDepartHeaderName(commonRequestDTO.getDepartHeaderName());         return commonRequestDTO;     }     return null; }

 

改造完成,再测试,发现这段代码耗时已经到ms级了。整体方法耗时也控制在了10s以内。


那么,回过头来分析,我们看程序里redis-RedisTemplate配置,valueSerializer使用Jackson2JsonRedisSerializer,Jackson2JsonRedisSerializer序列化使用ObjectMapper。

/**  * RedisTemplate配置  * @param lettuceConnectionFactory  * @return  */ @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {     // 设置序列化     Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);     ObjectMapper om = new ObjectMapper();     om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);     om.enableDefaultTyping(DefaultTyping.NON_FINAL);     jackson2JsonRedisSerializer.setObjectMapper(om);     // 配置redisTemplate     RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();     redisTemplate.setConnectionFactory(lettuceConnectionFactory);     RedisSerializer<?> stringSerializer = new StringRedisSerializer();     redisTemplate.setKeySerializer(stringSerializer);// key序列化     redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化     redisTemplate.afterPropertiesSet();     return redisTemplate; }


ObjectMapper在序列化时,会将所有的字段序列化,无论这些字段是否有值(是否为null)。再看CommonRequestDTO,有多达22个属性,可见在本案List<CommonRequestDTO>中有223个元素时,数据体积无形中增大很多。通过下面对ObjectMapper的测试代码来比较一下,很明显可以看到单个对象序列化后在数据量方面的差异:

@Test public void testObjectMapper2() throws JsonProcessingException {     ObjectMapper om = new ObjectMapper();     om.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY)             .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);     System.out.println("序列化所有字段(无论这些字段是否有值) ↓ ↓ ↓");     System.out.println(new String(om.writeValueAsBytes(new CommonRequestDTO())));       om = new ObjectMapper();     om.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY)             .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)             .setSerializationInclusion(JsonInclude.Include.NON_NULL);     System.out.println("不序列化空值字段 ↓ ↓ ↓");     System.out.println(new String(om.writeValueAsBytes(new CommonRequestDTO()))); }
序列化所有字段(无论这些字段是否有值) ↓ ↓ ↓ ["com.emax.memberaccount.restapi.vo.CommonRequestDTO",{"enterpriseId":null,"enterpriseBizId":null,"enterpriseName":null,"saleId":null,"product":null,"entStatus":null,"departId":null,"agentId":null,"levyId":null,"departHeaderId":null,"saleIds":null,"enterpriseIds":null,"productList":null,"createTimeBegin":null,"createTimeEnd":null,"saleName":null,"departName":null,"departHeaderName":null,"ifDepartHeader":null,"loginSalerId":null,"selectEnterpriseId":null,"orderEndTime":null,"enterpriseProductDTOS":null}] 不序列化空值字段 ↓ ↓ ↓ ["com.emax.memberaccount.restapi.vo.CommonRequestDTO",{}]

 

    • 因此,我们的程序有必要加上这个控制,即只序列化非空字段。
      另外,就像我之前经常提到的,会 is one thing,会用 is another。本案也再一次敲响了警钟:在使用redis分布式缓存时,尤其控制缓存大对象,更要严禁高频访问大对象缓存。

标签:commonRequestDTO,om,null,CommonRequestDTO,300s,new,10s,序列化,优化
From: https://www.cnblogs.com/buguge/p/16744494.html

相关文章

  • 资源画像,看得见的容器资源优化助手
    作者:张佐玮(佑祎)背景介绍K8s为集群资源提供了良好的抽象,用户可以直接根据应用的资源需求填写容器资源规格,这种方式有效提升了集群资源的管理效率。然而,一直以来,容器资源......
  • 如何在 Power BI 中进行优化
    如何在PowerBI中进行优化Optimization1)删除不必要的列和行:过滤仅报告所需的数据。它会减小尺寸。2)使用聚合表:每当我们通过直接查询连接时,它基本上有助于提高大......
  • 前端面试前端性能优化篇
    不论是什么样的前端面试,总会问到的一个问题:前端性能优化。相信如果这个问题没有答好,在面试中会很被动。于是,趁着这个天天宅的时期,好好的整理了一番。Start~一、HTML优......
  • Web性能优化地图
    本文作者是来自360导航的前端开发工程师Berwin,W3C性能工作组成员,同时也是《深入浅出Vue.js》(待出版)的作者。本文转载自奇舞周刊。总结文章介绍我们都知道对于Web应......
  • 多目标优化 | NSGA-II进阶教程(全网首个三目标优化教程)
    我们在​​多目标优化|基于NSGA-II的多目标0-1背包问题求解(附matlab代码)​​讲解了使用NSGA-II求解两个目标(总价值和总体积)的01背包问题,后台有小伙伴咨询小编说能否出一期......
  • 多目标优化 | 基于NSGA-II的多目标0-1背包问题求解(附matlab代码)
    多目标0-1背包问题小编已经在​​基于粒子群算法的多目标搜索算法讲解(附MATLAB代码)​​这篇推文详细介绍过,NSGA-II小编已经在​​NSGA-II多目标优化算法讲解(附MATLAB代码)​......
  • sshd服务(1)优化ssh连接速度,解决等待时间长问题
    参考文档优化ssh连接速度,解决等待时间长问题、ssh持久化连接优化ansible修改ssh配置文件:/etc/ssh/sshd_config1、关闭DNS反查使用了dns反查,这样的话当ssh某个IP时,系......
  • Vue 超长列表渲染性能优化
    参考:https://juejin.cn/post/6979865534166728711#heading-3组件懒加载参考:https://github.com/xunleif2e/vue-lazy-component......
  • 索引优化与查询优化
    目录1、数据准备2、索引失效案例2.1全值匹配我最爱2.2最佳左前缀法则2.3主键插入顺序2.4计算、函数、类型转换(自动或手动)导致索引失效2.5类型转换导致索引失效2.6待......
  • 夯实基础之tcp优化传输数据性能
    tcp传输数据性能提升在前面介绍的是三次握手和四次挥手的优化策略,接下来主要介绍的是TCP传输数据时的优化策略。TCP连接是由内核维护的,内核会为每个连接建立内存缓......