接口的性能优化(前端、后端、数据库)
主要通过三方面进行优化
- 前端
- 后端
- 数据库
前端优化
接口拆分
不要搞一个大而全的接口,要区分核心与非核心的接口,不然核心接口就会被非核心接口拖累
或者一个接口中大部分返回都很快,但是被其中某个逻辑拖累,导致整个接口都很慢,这时候就可以把这个慢的逻辑抽出来,单独做一个接口
什么是核心呢?比如你是视频或者直播网站,那么你的视频、直播的内容就是核心,要先调用视频、直播的接口,保证核心内容能够正常加载,然后再加载评论、礼物等接口。
当然接口的拆分也不宜过多,因为每次接口的请求与断开也都会消耗资源。
按需加载
如果你的接口是返回一篇文章,如果文章很长,则不要直接返回全部内容(尤其设计多图片、视频),可根据用户阅读进度进行逐步加载。
如果是返回列表,则不要全部返回,而要分页显示。
及时反馈用户状态
有些接口返回较慢,用户触发后(比如点击按钮),可能无法立即返回结果。
这时候如果等待接口返回结果后再给用户反馈,那么用户在等待的过程中就会以为自己的操作没有生效,这时候不仅用户体验不好,同时用户还可能会重复点击,造成多次接口访问,同时也会消耗资源。
为避免这种情况,要求用户触发某个动作时,要立刻给用户一个反馈,比如显示“加载中,请等待。。”等字样。
当然前端也可以通过其他方式来限制用户重复点击的问题,比如设置过期时间,加锁等方式
接口并行访问
如果接口之前没有依赖关系,可并行访问,加快访问速度
静态资源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