后端API接口性能优化的方法,那叫一个优雅!

2023-06-0717:29:19后端程序开发Comments906 views字数 3217阅读模式

接口性能优化对于从事后端开发的同学来说,肯定再熟悉不过了,有的公司将接口性能加入到绩效考核中。今天和大家聊聊开发中常用的接口优化方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

索引

对于查询大家首先会想到 sql 是否加索引了或者是否走索引了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

我们可以通过 explain 命令看下索引的使用情况文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

explain select * from usero where userId like '%234';

SQL优化方式文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

建立索引原则参考:MySQL索引文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

深分页问题

MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL改写。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

标签记录法文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

select  id,name FROM user where id > 100000 limit 10;

延迟关联法文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

延迟关联法,就是把条件转移到主键索引树,然后减少回表。优化后的SQL如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

select  a.id,a.name,a.balance FROM user a INNER JOIN (SELECT b.id FROM user b WHERE b.create_time > '2022-05-19' limit 100000, 10) AS c on a.id= c.id;

先通过create_time二级索引树查询到满足条件的主键ID,再与原表通过主键ID内连接,这样后面直接走了主键索引了,同时也减少了回表。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

使用缓存

缓存是一种空间换时间的思想,把要查的数据,放好到缓存里面,需要时,直接查缓存,而避免去查数据库或者计算的过程文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

缓存通常有两种:一种是本地缓存也就是 JVM 缓存,另一种是 Memcached/Redis 类的集中式缓存。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

使用缓存也可以采用预取思想提前把将来可能需要的数据计算好,放到缓存中,等需要的时候,去缓存取就行。可以通过定时任务定时去更新缓存。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

使用缓存需要考虑几个问题:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

  • 缓存的高可用问题。如果缓存宕机,是否会压垮数据库?
  • 缓存穿透。虽然缓存没有宕机,但是某些 Key 发生了大量查询,并且这些Key 都不在缓存里,导致短时间内大量请求压垮数据库。
  • 缓存击穿。指一个热点 Key,大并发集中对这一个点进行访问,当这个 Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库。
  • 大量的热 Key 过期。某些 Key 失效,大量请求在短时间内写入并压垮数据库,也就是缓存雪崩。
  • 缓存和数据库一致性问题。

池化思想

池化思想解决的问题就是避免重复创建对象或创建连接,可以重复利用,避免不必要的损耗,毕竟创建销毁也会占用时间。我们常见的线程池、数据库连接池都是池化思想。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

我们在写代码时候可以利用这种思想来优化接口性能,凡是不阻碍主流程的业务逻辑,都可以异步化,放到后台去做。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

异步处理

异步思想:针对耗时比较长且不是结果必须的逻辑,可以考虑放到异步执行,这样能降低接口耗时。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

比如:用户注册成功后,短信邮件通知,也是可以异步处理文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

异步的实现方式,可以用线程池、异步注解、异步调用,也可以用消息队列实现文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

List<List<Long>> allIds = Lists.partition(ids,200);

final List<User> result = Lists.newArrayList();
allIds.stream().forEach((batchIds) -> {
   CompletableFuture.supplyAsync(() -> {
        result.addAll(remoteCallUser(batchIds));
        return Boolean.TRUE;
    }, executor);
})

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

串行改并行

串行就是,当前执行逻辑必须等上一个执行逻辑结束之后才执行,并行就是两个执行逻辑同时进行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

如果是同步调用,则所消耗的总时间 T=T1+T2 +T3;如果是异步调用,则所消耗的总时间 T=Max(T1, T2,T3)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

串行条件:3 个调用之间没有耦合关系,可以并行。如果必须在拿到第 1 个调用的结果之后,根据结果再去调用第 2、第 3 个接口,就不能做异步调用了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

批量处理

批量操作数据库,主要是针对同时保存多个数据。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

优化前:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

//for循环单笔入库
for(User user:userList){
  insert(user);  
}

优化后:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

batchInsert(userList);

避免大事务

大事务就是运行时间长的事务。由于事务一致不提交,就会导致数据库连接被占用,即并发场景下,数据库连接池被占满,影响到别的请求访问数据库,影响别的接口性能,甚至有可能拖垮数据库。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

因此,为了优化接口,我们要规避大事务问题。我们可以通过这些方案来规避大事务:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

  • RPC远程调用不要放到事务里面
  • 查询相关的操作,尽量放到事务之外
  • 事务中避免处理太多数据

锁粒度避免过粗

锁一般是为了在高并发场景下保护共享资源采用的一种手段,但是如果锁的粒度太粗,会很影响接口性能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

关于锁粒度:就是要锁的范围有多大,不管是jvm锁、redis分布式锁还是数据库锁,只需要在临界资源处加锁即可,不涉及共享资源的,不必要加锁。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

错误方式文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

        //非共享资源
        private void notShare(){
        }
        //共享资源
        private void share(){
        }
        private int wrong(){
            synchronized (this) {
                share();
                notShare();
            }
        }

正确方式:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

       //非共享资源
        private void notShare(){
        }
        //共享资源
        private void share(){
        }
        private int right(){
            notShare();
            synchronized (this) {
                share();

            }
        } 

优化程序结构

优化程序逻辑、程序代码,是可以节省耗时的。比如,程序创建多不必要的对象、或者程序逻辑混乱,多次重复查数据库、又或者实现逻辑算法不是最高效的,甚至出现死循环等等。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

复杂的逻辑条件,有时候调整一下顺序,就能让程序更加高效。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

有时候死循环是我们自己写的,例如下面这段代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

while(true) {
    if(condition) {
        break;
    }
    System.out.println("do samething");
}

如果condition条件非常复杂,一旦出现判断不正确,或者少写了一些逻辑判断,就可能在某些场景下出现死循环的问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

分库分表

当系统发展到一定的阶段,用户并发量大,会有大量的数据库请求,需要占用大量的数据库连接,同时会带来磁盘IO的性能瓶颈问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

此外,随着用户数量越来越多,产生的数据也越来越多,由于数据量太大,sql语句查询数据时,即使走了索引也会非常耗时。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

这时候就要分库分表了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

分库分表主要有两个方向:垂直水平文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

在水平方向(即数据方向)上,分库和分表的作用,其实是有区别的,不能混为一谈。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

  • 分库:是为了解决数据库连接资源不足问题,和磁盘IO的性能瓶颈问题。
  • 分表:是为了解决单表数据量太大,sql语句查询数据时,即使走了索引也非常耗时问题。此外还可以解决消耗cpu资源问题。
  • 分库分表:可以解决 数据库连接资源不足、磁盘IO的性能瓶颈、检索数据耗时 和 消耗cpu资源等问题。

总结

后端API接口性能优化的方法,那叫一个优雅!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/45721.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/45721.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定