谷粒商城项目性能优化记录

  1. 动静分离
    将css、js、img、html等静态界面放在nginx,动态界面从应用服务器获取

  2. JVM内存优化(尽可能的使内存大些,这样垃圾回收占用的时间便会减少)
    -Xmx1024m: jvm最大可用内存为1024m
    -Xms1024m: jvm启动时分配的内存为1024m,此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
    -Xmn512m: 新生代内存大小为512m,整个JVM内存大小=新生代大小 + 老年代大小 + 永久代大小

  3. 数据库索引
    pms_category中的paremt_cid(父节点分类id)设置索引,在三级分类查询过程中会有优化.

  4. 数据库的多次查询变成一次

  • 原来三级查询的方式
    先从数据库中查一级分类,再将一级分类的cat_id作为二级分类的parent_cid从数据库中查询二级分类信息,再将二级分类的cat_id作为三级分类的parent_cid查询三级分类信息.
    需要向数据库中查询三次

  • 优化的查询方式
    从数据库中获取分类表中所有的数据,进行三次过滤操作,即一级分类的parent_cid=0,二级分类的parent_cid等于一级分类的cid,三级分类的parent_cid等于二级分类的cid.
    只需要向数据库中查询一次,虽然之后要有过滤操作,但是要比向数据库中查询快的多.

  1. 使用redis缓存
  • 应用场景
    • 即时性、数据一致性要求不高
    • 访问量大且更新频率不高的数据
  • 引用举例
    • 秒杀商品中的商品信息(库存等),显示的库存可能会大于实际库存,但是只要保证不多卖就可以.
  • redis缓存存在的问题及解决办法
    • 1.缓存穿透
      当查询一个一定不存在的数据,由于缓存不能命中,将去查询数据库,但是数据库中也没有这个记录,这将导致这个不存在的数据每次都要去存储层查询,失去了缓存的意义.而且会有利用不存在的数据进行攻击,致使数据库瞬间压力增大导致崩溃的风险.

    • 缓存穿透解决办法
      将null结果缓存,并加入短暂过期时间

    • 2.缓存雪崩
      在设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩

    • 缓存雪崩的解决办法
      原来的失效时间基础上增加一个随机值

    • 3.缓存击穿
      对于一些设置了过期时间的key,如果这些key在某些时间点会被超高并发访问,并且这个key在大量请求进来前刚好失效,那么所有对于这个key的查询都落到db,导致数据库瞬间压力增大导致崩溃.

    • 缓存击穿解决办法
      通过加锁,大量并发只让一个去查,其他请求等待,查到后首先将数据放入缓存然后再释放锁(如果先释放锁再将数据放入缓存,可能会导致多次查询数据库),其他请求获取到锁,先查缓存.

    • 4.缓存击穿本地锁的具体实现

      从redis中获取数据;
      if(redis中获取数据为null){
              
              
      	// 对当前对象加锁,因为springboot中的所有组件在容器中都是单例的
      	synchronized (this){
              
              
      		// 获取锁后再从redis中获取数据的原因是因为之前可能多个请求堵塞在锁外部(锁外部的redis获取数据为空)
      		从redis中获取数据;
      		if(redis中获取的数据不为空){
              
              
      			返回数据;
      		}else{
              
              
      			从数据库中获取数据;
      			将数据放到redis缓存中;
      		}
      	}
      }else{
              
              
      	return redis中获取的数据;
      }
      

      在分布式环境下存在的问题: 同一个服务中只会从数据库中获取一次,但是多个服务会获取多次.

    • 5.缓存击穿分布式锁具体实现链接

    • 6.缓存数据一致性(redis和数据库)解决方案
      方案一: 缓存的所有数据都有过期时间,数据过期下一次查询触发主动更新缓存
      方案二: 读写数据的时候,加上分布式读写锁

  1. 使用线程池异步编排

    @Override
        public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
          
          
            SkuItemVo skuItemVo = new SkuItemVo();
            CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(()->{
          
          
                // 1. sku基本信息获取 pms_sku_info
                SkuInfoEntity info = getById(skuId);
                skuItemVo.setInfo(info);
                return info;
            }, executor);
            CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res)->{
          
          
                // 3. 获取sku的销售属性组合
                List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSalesAttrsBySpuId(res.getSpuId());
                skuItemVo.setSaleAttr(saleAttrVos);
            }, executor);
            CompletableFuture<Void> descFuture  = infoFuture.thenAcceptAsync((res)->{
          
          
                // 4. 获取spu描述信息
                SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
                skuItemVo.setDesp(spuInfoDescEntity);
            },executor);
            CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync((res)->{
          
          
                // 5. 获取spu的规格参数信息
                List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
                skuItemVo.setGroupAttrs(attrGroupVos);
            }, executor);
    
            CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(()->{
          
          
                // 2. sku的图片信息
                List<SkuImagesEntity> skuImagesEntities = skuImagesService.list(new QueryWrapper<SkuImagesEntity>().eq("sku_id", skuId));
                skuItemVo.setImages(skuImagesEntities);
            }, executor);
    
            // 所有异步执行完成才返回,参数不用写infoFuture,因为saleAttrFuture, descFuture, baseAttrFuture都是在infoFuture的基础上执行的
            CompletableFuture.allOf(saleAttrFuture, descFuture, baseAttrFuture, imageFuture).get();
            return skuItemVo;
        }
    

猜你喜欢

转载自blog.csdn.net/qq_26496077/article/details/114841944