接口性能优化技巧
金蝶云社区-刘映希
刘映希
1人赞赏了该文章 91次浏览 未经作者许可,禁止转载编辑于2023年08月18日 20:13:06

  今天给大家分享一些接口优化小技巧

一、背景

     工作中我们建设的服务系统大多都会经历一个阶段:从上线开始少量用户、低并发场景到推广阶段过渡为大数据量、高并发场景。在这个过程中往往在收到了很多好评的同时也收到了很多对性能的吐槽。刚刚收到吐槽的时候,我们的心情可能是这样的:


image.png


      当越来越多对性能的吐槽反馈到我们这里的时候,我们意识到接口性能问题的优先级必须提高了,然后我们就跟踪了 1 周的接口性能监控,这个时候我们的心情可能是这样的:


image.png


二、哪些问题会引起接口性能问题?

      这个问题的答案非常多,需要根据自己的业务场景具体分析,这里做一个不完全统计:

  • 数据库慢查询

  • 业务逻辑复杂

  • 机器问题

  • 万金油解决方式

三、问题解决

  • 慢查询(基于 mysql)

①深度分页

      所谓的深度分页问题,涉及到 mysql 分页的原理。通常情况下,mysql 的分页是这样写的:

select name,code from student limit 100,20

含义当然就是从 student 表里查 100 到 120 这 20 条数据,mysql 会把前 120 条数据都查出来,抛弃前 100 条,返回 20 条。当分页所以深度不大的时候当然没问题,随着分页的深入,sql 可能会变成这样:

select name,code from student limit 1000000,20

这个时候,mysql 会查出来 1000020 条数据,抛弃 1000000 条,如此大的数据量,速度一定快不起来。那如何解决呢?一般情况下,最好的方式是增加一个条件:

select name,code from student where id>1000000  limit 20

这样,mysql 会走主键索引,直接连接到 1000000 处,然后查出来 20 条数据。但是这个方式需要接口的调用方配合改造,把上次查询出来的最大 id 以参数的方式传给接口提供方。

②未加索引

      这个是最容易解决的问题,我们可以通过下面的方式查看某张表的索引

show create table xxxx(表名)

顺便提一下,加索引之前,需要考虑一下这个索引是不是有必要加,如果加索引的字段区分度非常低,那即使加了索引也不会有很大效果。另外,加索引的 alter 操作,可能引起锁表,执行 sql 的时候一定要在低峰期(血泪史!!!!)

③索引失效

      这个是慢查询最不好分析的情况,虽然 mysql 提供了 explain 来评估某个 sql 的查询性能,其中就有使用的索引。但是为啥索引会失效呢?大体上,可能引起索引失效的原因有这几个(可能不完全):

image.png

④in元素过多

      如果一个查询有 in,in 的条件加了合适的索引,这个时候的 sql 还是比较慢就可以高度怀疑是 in 的元素过多。一旦排查出来是这个问题,解决起来也比较容易,可以把元素分个组,每组查一次,想再快的话,可以再引入多线程,进一步的,如果in的元素量大到一定程度还是快不起来,这种最好还是有个限制:

select id from student where id in (1,2,3 ...... 1000limit 200

业务逻辑复杂

①循环调用

      这种情况,一般都循环调用同一段代码,每次循环的逻辑一致,前后不关联。

②顺序调用

      如果不是类似上面循环调用,而是一次次的顺序调用,而且调用之间没有结果上的依赖,那么也可以用多线程的方式进行,例如:

image.png

| 机器问题(fullGC,机器重启,线程打满)

      造成这个问题的原因非常多,定时任务过大引起 fullGC,代码存在线程泄露引起 RSS 内存占用过高进而引起机器重启等待诸多原因。需要结合各种监控和具体场景具体分析,进而进行大事务拆分、重新规划线程池等工作。

| 万金油解决方式

      万金油解决方式往往能解决大部分的接口缓慢的问题,而且也往往是我们解决接口效率问题的最终解决方案。当我们实在是没有办法排查出问题,或者实在是没有优化空间的时候,可以尝试这种万金油的方式。

①缓存

      缓存是一种空间换取时间的解决方案,是在高性能存储介质上(例如:内存、SSD 硬盘等)存储一份数据备份。当有请求打到服务器的时候,优先从缓存中读取数据。如果读取不到,则再从硬盘或通过网络获取数据。由于内存或 SSD 相比硬盘或网络 IO 的效率高很多,则接口响应速度会变快非常多。缓存适合于应用在数据读远远大于数据写,且数据变化不频繁的场景中。

从技术选型上看,有这些:

  • 简单的map

  • 缓存中间件:redis、tair、memcached

②回调 or 反查

      这种方式往往是业务上的解决方式,在订单或者付款系统中应用的比较多。

image.png

      当我们付款的时候,需要调用一个专门的付款系统接口,该系统经过一系列验证、存储工作后还要调用银行接口以执行付款。由于付款这个动作要求十分严谨,银行侧接口执行可能比较缓慢,进而拖累整个付款接口性能。这个时候我们就可以采用 fast success 的方式:当必要的校验和存储完成后,立即返回 success,同时告诉调用方一个中间态“付款中”。而后调用银行接口,当获得支付结果后再调用上游系统的回调接口返回付款的最终结果“成功”or“失败”。这样就可以异步执行付款过程,提升付款接口效率。

      当然,为了防止多业务方接入的时候回调接口不统一,可以把结果抛进 kafka,让调用方监听自己的结果。

image.png


本文转载自:公共号金蝶云·天梯

作者:孙玉飞

原文链接:公共号金蝶云·天梯

赞 1