不扒瞎,这个程序让我从300s优化到了10s(优化差的3a)

  本篇文章为你整理了不扒瞎,这个程序让我从300s优化到了10s(优化差的3a)的详细内容,包含有优化多少 优化差的3a 03t优化 升级优化 不扒瞎,这个程序让我从300s优化到了10s,希望能帮助你了解 不扒瞎,这个程序让我从300s优化到了10s。

   会 is one thing,会用 is another。本案也再一次敲响了警钟:在使用redis分布式缓存时,尤其控制缓存大对象,更要严禁高频访问大对象缓存。

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

  

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

  

  

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

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

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

  

  

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

  贴出来这段代码:

  
publicCommonRequestDTO 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());

  returncommonRequestDTO;

  }

  returnnull;

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

  

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

  

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

  
staticTimedCache String ,List CommonRequestDTO cache= cn.hutool.cache.CacheUtil.newTimedCache(SaleCommonConstant.EXPIRY_SECONDS);

  

  * 查询销售与部门的关联关系

  * @param saleId

  * @return

  */

  publicCommonRequestDTO 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());

  returncommonRequestDTO;

  }

  returnnull;

  
 

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

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

  
@Bean

  publicRedisTemplate String, Object redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {

  // 设置序列化

  Jackson2JsonRedisSerializer Object jackson2JsonRedisSerializer =newJackson2JsonRedisSerializer Object (Object.class);

  ObjectMapper om =newObjectMapper();

  om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);

  om.enableDefaultTyping(DefaultTyping.NON_FINAL);

  jackson2JsonRedisSerializer.setObjectMapper(om);

  // 配置redisTemplate

  RedisTemplate String, Object redisTemplate =newRedisTemplate String, Object

  redisTemplate.setConnectionFactory(lettuceConnectionFactory);

  RedisSerializer ? stringSerializer =newStringRedisSerializer();

  redisTemplate.setKeySerializer(stringSerializer);// key序列化

  redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化

  redisTemplate.afterPropertiesSet();

  returnredisTemplate;

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

  
@Test

  publicvoidtestObjectMapper2()throwsJsonProcessingException {

  ObjectMapper om =newObjectMapper();

  om.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY)

  .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

  System.out.println("序列化所有字段(无论这些字段是否有值) ↓ ↓ ↓");

  System.out.println(newString(om.writeValueAsBytes(newCommonRequestDTO())));

  

  om =newObjectMapper();

  om.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY)

  .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)

  .setSerializationInclusion(JsonInclude.Include.NON_NULL);

  System.out.println("不序列化空值字段 ↓ ↓ ↓");

  System.out.println(newString(om.writeValueAsBytes(newCommonRequestDTO())));

  
序列化所有字段(无论这些字段是否有值) ↓ ↓ ↓

  ["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分布式缓存时,尤其控制缓存大对象,更要严禁高频访问大对象缓存。

  
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自,转载请注明原文链接:https:///buguge/p/16744494.html

  以上就是不扒瞎,这个程序让我从300s优化到了10s(优化差的3a)的详细内容,想要了解更多 不扒瞎,这个程序让我从300s优化到了10s的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: