forked from whx123/JavaHome
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
## 前言 | ||
最近对外接口偶现504超时问题,真枪实弹搞了一次接口性能优化。在这里结合优化过程,总结了接口优化的八个要点,希望对大家有帮助呀~ | ||
- 数据量比较大,批量操作数据入库 | ||
- 耗时操作考虑异步处理 | ||
- 恰当使用缓存 | ||
- 优化程序逻辑、代码 | ||
- SQL优化 | ||
- 压缩传输内容 | ||
- 考虑使用文件/MQ等其他方式暂存,异步再落地DB | ||
- 跟产品讨论需求最恰当,最舒服的实现方式 | ||
|
||
嘻嘻,先看一下我们对外转账接口的大概流程吧 | ||
![](https://user-gold-cdn.xitu.io/2020/5/30/1726375c0d0162f3?w=1393&h=586&f=png&s=50348) | ||
|
||
### 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条 | 611 | 449 | | ||
| 1000条 | 1420 | 1128 | | ||
|
||
**解析** | ||
- 批量插入性能更好,更加省时间,为什么呢? | ||
|
||
``` | ||
打个比喻:假如你需要搬一万块砖到楼顶,你有一个电梯,电梯一次可以放适量的砖(最多放500), | ||
你可以选择一次运送一块砖,也可以一次运送500,你觉得哪种方式发方便,时间消耗小? | ||
``` | ||
|
||
|
||
### 2.耗时操作考虑异步处理 | ||
|
||
**优化前:** | ||
|
||
|
||
|
||
|
||
**优化后:** | ||
|
||
![](https://user-gold-cdn.xitu.io/2020/5/30/172636b9f5238802?w=999&h=644&f=png&s=67707) | ||
|
||
**性能对比:** | ||
|
||
假设一个联行号匹配6ms | ||
| |同步| 异步| | ||
|-----|-----|------| | ||
| 500条 | 3000ms | 0 | | ||
| 1000条| 6000ms | 0| | ||
|
||
|
||
**解析:** | ||
- 因为联行号匹配比较耗时,放在异步处理的话,可以同步联机返回可以省掉这部分时间,大大提升接口性能,并且不会影响到转账主流程功能。 | ||
- 除了这个例子,平时我们类似功能,如用户注册成功后,短信邮件通知,也是可以异步处理的,这个优化点香饽饽的~ | ||
- 所以,太耗时的操作,在不影响主流程功能的情况下,可以考虑开子线程异步处理的啦。 | ||
|
||
### 3.恰当使用缓存 | ||
在适当的业务场景,恰当地使用缓存,是可以大大提高接口性能的。这里的缓存包括:Redis,JVM本地缓存,memcached,或者Map等。 | ||
|
||
这次转账接口,使用到缓存啦,举个简单例子吧~ | ||
|
||
**优化前:** | ||
|
||
|
||
![](https://user-gold-cdn.xitu.io/2020/5/30/17263c548352f480?w=396&h=719&f=png&s=36528) | ||
|
||
**优化后:** | ||
|
||
|
||
![](https://user-gold-cdn.xitu.io/2020/5/30/17263cc73ccd1e76?w=723&h=785&f=png&s=70764) | ||
|
||
**解析:** | ||
- 把热点数据放到缓存,不用每次查询都去DB拉取,节省了这部分查SQL的耗时,美滋滋呀~ | ||
- 当然,不是什么数据都适合放到缓存的哦,访问比较频繁的热点数据才考虑缓存起来呢~ | ||
|
||
### 4.优化程序逻辑、代码 | ||
优化程序逻辑,优化程序代码,是可以节省耗时的。 | ||
|
||
我这里也就本次的转账接口优化,举个例子吧~(优化前,联行号查询了两次) | ||
|
||
**优化前:** | ||
|
||
``` | ||
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循环,是否重复实例化对象等等,这些都是我们需要关注的优化点。 | ||
|
||
之前我这篇文章,也提了几个优化点啦,有兴趣的朋友可以看一下哈~ | ||
|
||
[写代码有这些想法,同事才不会认为你是复制粘贴程序员](https://juejin.im/post/5dfe2e72518825125f39a2de#heading-1) | ||
|
||
### 5.优化SQL | ||
|
||
很多时候,你的接口性能瓶颈就在SQL这里,慢查询需要我们重点关注的呢。 | ||
|
||
我们可以通过这些方式优化我们的SQL: | ||
- 加索引 | ||
- 避免返回不必要的数据 | ||
- 优化sql结构 | ||
- 分库分表 | ||
- 读写分离 | ||
|
||
有兴趣的朋友可以看一下我这篇文章呢,很详细的SQL优化点: | ||
|
||
[后端程序员必备:书写高质量SQL的30条建议](https://juejin.im/post/5e624d156fb9a07ca80ab6f2) | ||
|
||
|
||
### 6.压缩传输内容 | ||
|
||
压缩传输内容,让文件更小,因此传输会更快啦。10M带宽,传输10k的报文,一般比传输1M的会快呀;打个比喻,一匹千里马,它驮着一百斤的货跑得快,还是驮着10斤的货物跑得快? | ||
|
||
|
||
传输100个转账对账对象耗时: | ||
|
||
传输500个转账对象的耗时: | ||
|
||
|
||
**解析:** | ||
- 如果你的接口性能不好,然后传输报文很大,这时候是可以考虑压缩文件内容传输的,最后优化效果可能很不错哦~ | ||
|
||
|
||
### 7.考虑使用文件/MQ等其他方式暂存,异步再落地DB | ||
如果数据太大,落地数据库实在是慢,可以考虑先用文件的方式保存,或者考虑MQ,先落地,再异步保存到数据库~ | ||
> 本次转账接口,如果是并发开启,10个并发度,每个批次1000笔数据,数据库插入会特别耗时,大概10秒左右,这个跟我们的数据库机制有关,并发情况下,因为优先保证同步,所以并行的插入变成串行啦,就很耗时。 | ||
**优化前:** | ||
|
||
![](https://user-gold-cdn.xitu.io/2020/5/30/172649d6bd1017bf?w=704&h=490&f=png&s=43540) | ||
|
||
**优化后:** | ||
|
||
![](https://user-gold-cdn.xitu.io/2020/5/30/17264a156b8b9691?w=778&h=518&f=png&s=50459) | ||
**解析:** | ||
- 如果你的耗时瓶颈就在数据库插入操作这里了,那就考虑文件保存或者MQ或者其他方式暂存吧,文件保存数据,对比一下耗时,有时候会有意想不到的效果哦。 | ||
|
||
|
||
### 8.跟产品讨论需求最恰当,最舒服的实现方式 | ||
这点个人觉得还是很重要的,有些需求需要好好跟产品沟通的。 | ||
|
||
> 比如有个用户连麦列表展示的需求,产品说要展示所有的连麦信息,如果一个用户的连麦列表信息好大,你拉取所有连麦数据回来,接口性能就降下来啦。如果产品打桩分析,会发现,一般用户看连麦列表,也就看前几页~因此,奸笑,哈哈~ 其实,那个超大分页加载问题也是类似的。即limit +一个超大的数,一般会很慢的~~ | ||
### 总结 | ||
|
||
本文呢,基于一次对外接口耗时优化的实践,15秒降到4秒左右,总结了优化接口性能的八个点,希望对大家日常开发有帮助哦~嘻嘻,有兴趣可以逛逛我的github哈,本文会收藏到github里滴 | ||
> https://github.com/whx123/JavaHome | ||
|
||
### 公众号 | ||
![](https://user-gold-cdn.xitu.io/2020/5/16/1721b50d00331393?w=900&h=500&f=png&s=389569) | ||
- 欢迎关注我个人公众号,交个朋友,一起学习哈~ | ||
|
||
|
||
|