性能调优接口平台服务性能优化
Posted sysu_lluozh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能调优接口平台服务性能优化相关的知识,希望对你有一定的参考价值。
一、问题背景
用户反馈接口平台后台服务接口处理时间慢,导致加载页面或某些操作请求时间特别长,很影响用户体验
可以看到接口请求普遍很慢,POST请求尤其明显
二、代码分析
可以分析对应几个接口的源码,发现大部分操作均是db操作和数据处理,并未发现可疑点
三、cProfiler分析
使用【调优工具】python性能分析工具cProfiler 针对耗时特别长的接口,比如修改接口的这个功能模块进行分析
@do_cprofile('./mkm_modify_iv.prof')
def modify_iv_content(self, project_id, iv_id, iv_data):
"""
更新接口
"""
生成mkm_run.png分析图:
可以看到90%的时间在数据库连接和操作,接下来分为两个点去优化,一个是数据库的连接池的使用减少数据库连接的耗时,一个是数据库执行sql的优化
四、数据库连接池优化
主要使用【python】DBUtils数据库连接池 的方式创建数据库连接池,但是这里遇到几个问题
4.1 问题一:DBUtils版本
直接pip install DBUtil
下载包,当前最新版本是2.0.2
有个问题,即网上的资源的包的引用基本上是:
from DBUtils.PooledDB import PooledDB
这个其实是1.x版本的方式,在2.x版本中引用方式为
from dbutils.PooledDB import PooledDB
可以查看DBUtils的更新日志 :
4.2 问题二:Lost connection to mysql server
服务部署后,前端发起批量接口的请求,这时某些conn会报这个错误
pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query ([Errno 104] Connection reset by peer)')
如果服务启动后,单个接口连续请求,并不会引发该错误,然后出现该异常一段时间后连接也是正常
查看连接池的配置
POOL = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3,
# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。
ping=0,
# ping MySQL服务端,检查是否服务可用。
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='test',
charset='utf8'
)
故怀疑是否因为连接池初始化时:
-
链接池中至少创建的空闲的链接2个,连接不够用导致?
将mincached
设置为5、10、甚至50该问题仍然存在 -
链接池中至少创建的空闲的链接2个,初始化的连接异常导致?
将mincached
设置为0,该问题不再出现(但是并没有定位出这个问题的真正原因)
五、数据库执行sql优化
连接复用的问题解决了,现在还需要继续优化sql语句
5.1 定位执行耗时的sql
在这里使用统计函数运行耗时的装饰器
# 计算函数执行耗时
def time_it(func):
def call_fun(*args, **kwargs):
start_time = time.time()
f = func(*args, **kwargs)
time_spend = int(1000*(time.time() - start_time))
if time_spend>100:
logger.warning('*****************************************%s() run time:%s ms %s' % (func.__name__, time_spend, args))
return f
return call_fun
在sql的query
和operate
函数中使用该装饰器,耗时超过100ms的sql语句记录下来一一分析
5.2 优化耗时的sql语句
根据EXPLAIN
初步分析,执行耗时的sql语句基本上是因为索引的原因
接下来看一个有索引,但是索引未正确创建的栗子
5.2.1 sql语句
sql语句如下:
SELECT project_id FROM interface_view_exec_history WHERE iv_id = 12;
5.2.2 EXPLAIN
EXPLAIN这条sql语句:
EXPLAIN SELECT project_id FROM interface_view_exec_history WHERE iv_id = 12;
执行结果如下:
发现进行了全表扫描
5.2.3 查看索引
查看一下该表的索引:
show index from interface_view_exec_history;
执行结果如下:
5.2.4 联合索引
根据上面的表索引知道,有创建了联合索引username_iv_id
,但是由于该联合索引中username的Seq_in_index为1,而iv_id为2,故上面的SELECT执行中未命中该联合索引
根据服务中对该联合索引的使用,将iv_id修改Seq_in_index为1,username为2
此时再次执行EXPLAIN
可以看到,命中索引,扫描行数为1,在正式环境中数据量8w条,sql执行时间从300ms降低为10ms以内
以上是关于性能调优接口平台服务性能优化的主要内容,如果未能解决你的问题,请参考以下文章