优化接口性能的八个建议

前言

最近对外接口偶现504超时问题,原因是代码执行时间过长,超过nginx配置的15秒,然后真枪实弹搞了一次接口性能优化。在这里结合优化过程,总结了接口优化的八个要点,希望对大家有帮助呀~

  • 数据量比较大,批量操作数据入库
  • 耗时操作考虑异步处理
  • 恰当使用缓存
  • 优化程序逻辑、代码
  • SQL优化
  • 压缩传输内容
  • 考虑使用文件/MQ等其他方式暂存,异步再落地DB
  • 跟产品讨论需求最恰当,最舒服的实现方式

嘻嘻,先看一下我们对外转账接口的大概流程吧图片

1.数据量比较大,批量操作数据入库

优化前:


    //for循环单笔入库
    for(TransDetail detail:list){
      insert(detail);  
    }


    优化后:


      // 批量入库,mybatis demo实现
      <insert id="insertBatch" parameterType="java.util.List">
      insert into trans_detail( id,amount,payer,payee) values
       <foreach collection="list" item="item" index="index" separator=",">(
          #{item.id},	#{item.amount},
          #{item.payer},#{item.payee}
        )
      </foreach>
      </insert>


      性能对比:

      单位(ms)for循环单笔入库批量入库
      500条14321153
      1000条18761425

      解析

      • 批量插入性能更好,更加省时间,为什么呢?


        打个比喻:假如你需要搬一万块砖到楼顶,你有一个电梯,电梯一次可以放适量的砖(最多放500),你可以选择一次运送一块砖,也可以一次运送500,你觉得哪种方式更方便,时间消耗更少?


        2.耗时操作考虑异步处理

        耗时操作,考虑用异步处理,这样可以降低接口耗时。本次转账接口优化,匹配联行号的操作耗时有点长,所以优化过程把它移到异步处理啦,如下:

        优化前:

        图片

        优化后

        匹配联行号的操作异步处理

        图片

        性能对比:

        假设一个联行号匹配6ms


        同步异步
        500条3000ms~
        1000条6000ms~

        解析:

        • 因为联行号匹配比较耗时,放在异步处理的话,同步联机返回可以省掉这部分时间,大大提升接口性能,并且不会影响到转账主流程功能。
        • 除了这个例子,平时我们类似功能,如用户注册成功后,短信邮件通知,也是可以异步处理的,这个优化建议香饽饽的~
        • 所以,太耗时的操作,在不影响主流程功能的情况下,可以考虑开子线程异步处理的啦。

        3.恰当使用缓存

        在适当的业务场景,恰当地使用缓存,是可以大大提高接口性能的。这里的缓存包括:Redis,JVM本地缓存,memcached,或者Map等。

        这次转账接口,使用到缓存啦,举个简单例子吧~

        优化前

        以下是输入用户账号,匹配联行号的流程图

        图片

        优化后:

        恰当使用缓存,代替查询DB表,流程图如下:

        图片

        解析:

        • 把热点数据放到缓存,不用每次查询都去DB拉取,节省了这部分查SQL的耗时,美滋滋呀~
        • 当然,不是什么数据都适合放到缓存的哦,访问比较频繁的热点数据才考虑缓存起来呢~

        4. 优化程序逻辑、代码

        优化程序逻辑、程序代码,是可以节省耗时的。

        我这里就本次的转账接口优化,举个例子吧~

        优化前:

        优化前,联行号查询了两次(检验参数一次,插入DB前查询一次),如下伪代码:


          punlic void process(Req req){
          //检验参数,包括联行号(前端传来的payeeBankNo可以为空,但是如果后端没匹配到,会抛异常)
          checkTransParams(Req req);
          //Save DB
          saveTransDetail(req);
          }

          void checkTransParams(Req req){
          //check Amount,and so on.
          checkAmount(req.getamount);
          //check payeebankNo
          if(Utils.isEmpty(req.getPayeeBankNo())){
          String payeebankNo = getPayeebankNo(req.getPayeeAccountNo);
          if(Utils.isEmpty(payeebankNo){
          throws Exception();
          }
          }
          }

          int saveTransDetail(req){
          String payeebankNo = getPayeebankNo(req.getPayeeAccountNo);
          req.setPayeeBankNo(payeebankNo);
          insert(req);
          ...
          }


          优化后:

          优化后,只在校验参数的时候插叙一次,然后设置到对象里面~ 入库前就不用再查啦,伪代码如下:


            void checkTransParams(Req req){
                //check Amount,and so on.
                checkAmount(req.getamount);
                //check payeebankNo
                if(Utils.isEmpty(req.getPayeeBankNo())){
                    String payeebankNo = getPayeebankNo(req.getPayeeAccountNo);
                    if(Utils.isEmpty(payeebankNo){
                        throws Exception();
                    }
                }
                //查询到有联行号,直接设置进去啦,这样等下入库不用再插入多一次
                req.setPayeeBankNo(payeebankNo);
            }
            
            int saveTransDetail(req){
                insert(req);
                ...
            }


            解析:

            • 对于优化程序逻辑、代码,是可以降低接口耗时的。以上demo只是一个很简单的例子,就是优化前payeeBankNo查询了两次,但是其实只查一次就可以了。很多时候,我们都知道这个点,但就是到写代码的时候,又忘记了呀~所以,写代码的时候,留点心吧,优化你的程序逻辑、代码哦。
            • 除了以上demo这点,还有其它的点,如优化if复杂的逻辑条件,考虑是否可以调整顺序,或者for循环,是否重复实例化对象等等,这些适当优化,都是可以让你的代码跑得更快的。

            之前我这篇文章,也提了几个优化点噢,有兴趣的朋友可以看一下哈~

            5. 优化你的SQL

            很多时候,你的接口性能瓶颈就在SQL这里,慢查询需要我们重点关注的点呢。

            我们可以通过这些方式优化我们的SQL:

            • 加索引
            • 避免返回不必要的数据
            • 优化sql结构
            • 分库分表
            • 读写分离

            有兴趣的朋友可以看一下我这篇文章呢,很详细的SQL优化点:

            6.压缩传输内容

            压缩传输内容,文件变得更小,因此传输会更快啦。10M带宽,传输10k的报文,一般比传输1M的会快呀;打个比喻,一匹千里马,它驮着一百斤的货跑得快,还是驮着10斤的货物跑得快呢?

            解析:

            展开阅读全文

            本文系作者在时代Java发表,未经许可,不得转载。

            如有侵权,请联系nowjava@qq.com删除。

            编辑于

            关注时代Java

            关注时代Java