接口的性能优化(前端、后端、数据库)

主要通过三方面进行优化

  • 前端
  • 后端
  • 数据库

前端优化

接口拆分

不要搞一个大而全的接口,要区分核心与非核心的接口,不然核心接口就会被非核心接口拖累

或者一个接口中大部分返回都很快,但是被其中某个逻辑拖累,导致整个接口都很慢,这时候就可以把这个慢的逻辑抽出来,单独做一个接口

什么是核心呢?比如你是视频或者直播网站,那么你的视频、直播的内容就是核心,要先调用视频、直播的接口,保证核心内容能够正常加载,然后再加载评论、礼物等接口。

当然接口的拆分也不宜过多,因为每次接口的请求与断开也都会消耗资源。

按需加载

如果你的接口是返回一篇文章,如果文章很长,则不要直接返回全部内容(尤其设计多图片、视频),可根据用户阅读进度进行逐步加载。

如果是返回列表,则不要全部返回,而要分页显示。

及时反馈用户状态

有些接口返回较慢,用户触发后(比如点击按钮),可能无法立即返回结果。

这时候如果等待接口返回结果后再给用户反馈,那么用户在等待的过程中就会以为自己的操作没有生效,这时候不仅用户体验不好,同时用户还可能会重复点击,造成多次接口访问,同时也会消耗资源。

为避免这种情况,要求用户触发某个动作时,要立刻给用户一个反馈,比如显示“加载中,请等待。。”等字样。

当然前端也可以通过其他方式来限制用户重复点击的问题,比如设置过期时间,加锁等方式

接口并行访问

如果接口之前没有依赖关系,可并行访问,加快访问速度

静态资源CDN

静态资源包括图片、视频等媒体问题,同时也包括js、css、html等一些文本文件。相同的是这些文件都是静态,也就是短期内不会变化的问题。

这些文件就非常适合通过CDN进行加速分发

静态资源缓存

与上述原因相同,因为是静态资源,所以也可以缓存在本地

后端优化

限流、熔断与降级

限流是针对服务请求数量的一种自我保护机制,当请求数量超出服务的处理能力时,会自动丢弃新来的请求。

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

降级是将某些不重要的业务关闭,保证核心功能可用。降级的思想是丢车保帅。

防止重复点击

防止多次重复点击,每次接口调用,都会消耗后端资源。

可通过加锁的方式实现

使用多线程

涉及多个对象的操作,尤其是列表循环的操作,可以引入多线程,把之前的串行操作改为并行,大大提高效率

如果涉及到多个线程之前的等待,可是使用CountDownLatch、CyclicBarrier和Semaphore,可参考https://blog.csdn.net/CrankZ/article/details/83781380

异步

一些与主流程不相关的或者耗时较长的处理,可以改为异步,比如发送短信、邮件等

异步的方式有很多种,比如直接新建线程或者引入第三方MQ

缓存

根据我的经验,IO操作(包括与数据库的交互和网络接口的交互)都是占用耗时的大头。所以如果能适当针对这些IO操作加上缓存,将会大大的提高性能。

缓存主要分2类,本地缓存(Caffeine为代表)、远程缓存(Redis为代表),可针对不同的场景进行使用。

当然也可以结合两者,组成二级缓存,这里可以使用阿里开源的组件 https://github.com/alibaba/jetcache

缓存相关内容可参考我的另一篇文章 https://blog.csdn.net/CrankZ/article/details/80537115

本地缓存可参考我的另一篇文章 https://blog.csdn.net/CrankZ/article/details/90344348

数据库连接池

数据库的每次连接与关闭,都会消耗资源,如果每次都这样重新建立并销毁连接,这样会性能低下。

所以数据库连接池的建立多个数据库连接,并将这些连接组成一个连接池,由应用程序动态地对池中的连接进行申请、使用和释放。

数据库连接池可参考 https://blog.csdn.net/CrankZ/article/details/82874158

JVM优化

启动的内存大小、选择合适GC等

组件升级

升级底层组件,比如升级到Java21,在Java21中可以启用虚拟线程、使用新增的GC等

数据库优化

数据库选择

首先要针对不同的数据,选择合适的数据库

常规关系型数据除了常见的MySQL,还可以选择PostgreSQL,TiDB等

非关系型数据,比如大文本,JSON等,可以考虑MongoDB

如果涉及搜索的,可以使用Elasticsearch或者ClickHouse等

图数据库,比选择Neo4j等

下面以MySQL为代表,讲一些关系型数据库的优化

读写分离

增加从节点,从节点专注读请求,主节点专注处理写请求。

主库与从库的结构完全一样,一个主库可以有多个从库

可参考我另一篇文章 https://blog.csdn.net/CrankZ/article/details/84679742

分库分表

当单库单表无法满足需求时,可考虑分库分表。

这里不做赘述,可参考我另一篇文章 https://blog.csdn.net/CrankZ/article/details/84679742

归档历史数据,降低单表规模

MySQL并不适合存储大数据量,如果不对数据进行归档,数据库会持续膨胀,从而降低查询和写入的性能。为了满足大数据量的读写需求,需要定期对数据库进行归档。

在进行数据库设计时,需要事先考虑到对数据归档的需求。

如果有需要,可以考虑专门的数据仓库Hive或者HBase等

索引优化

避免索引失效,尽量保证每次查询都命中索引

可参考我另一篇文章 https://blog.csdn.net/CrankZ/article/details/80468760

参考

https://juejin.cn/post/7287420810318299190