当越来越多对性能的吐槽反馈到我们这里的时候,我们意识到,接口性能的问题的优先级必须提高了。然后我们就跟踪了1周的接口性能监控,这个时候我们的心情是这样的:
有20多个慢接口,5个接口响应时间超过5s,1个超过10s,其余的都在2s以上,稳定性不足99.8%。作为一个优秀的后端程序员,这个数据肯定是不能忍的,我们马上就进入了漫长的接口优化之路。本文就是对我们漫长工作历程的一个总结。
哪些问题会引起接口性能问题?
这个问题的答案非常多,需要根据自己的业务场景具体分析。这里做一个不完全的总结:
- 数据库慢查询
- 深度分页问题
- 未加索引
- 索引失效
- join过多
- 子查询过多
- in中的值太多
- 单纯的数据量过大
- 业务逻辑复杂
- 循环调用
- 顺序调用
- 线程池设计不合理
- 锁设计不合理
- 机器问题(fullGC,机器重启,线程打满)
1、慢查询(基于mysql)
1.1 深度分页
所谓的深度分页问题,涉及到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以参数的方式传给接口提供方,会有沟通成本(调用方:老子不改!)。
1.2 未加索引
这个是最容易解决的问题,我们可以通过
show create table xxxx(表名)查看某张表的索引。具体加索引的语句网上太多了,不再赘述。不过顺便提一嘴,加索引之前,需要考虑一下这个索引是不是有必要加,如果加索引的字段区分度非常低,那即使加了索引也不会生效。另外,加索引的alter操作,可能引起锁表,执行sql的时候一定要在低峰期(血泪史!!!!)
1.3 索引失效
这个是慢查询最不好分析的情况,虽然mysql提供了explain来评估某个sql的查询性能,其中就有使用的索引。但是为啥索引会失效呢?mysql却不会告诉咱,需要咱自己分析。大体上,可能引起索引失效的原因有这几个(可能不完全):
需要特别提出的是,关于字段区分性很差的情况,在加索引的时候就应该进行评估。如果区分性很差,这个索引根本就没必要加。区分性很差是什么意思呢,举几个例子,比如:
- 某个字段只可能有3个值,那这个字段的索引区分度就很低。
- 再比如,某个字段大量为空,只有少量有值;
- 再比如,某个字段值非常