记一次Django响应超慢的解决过程

  在本地windows机器开发的Django项目运行正常,放到服务器上后响应超慢,花了一整个工作日没找到原因(非常绝望),又花了一整个周末才找到原因和临时解决办法,如果你的项目超慢可以参考一下解决思路。

排查过程:

1.怀疑是Python环境问题,到服务器上各种虚拟环境版本进行尝试,无果。

2.因为用了mysql数据库,开始用pymysql包连接改动了一些参数,担心是驱动问题导致数据库查的慢,更换mysqlclient包后,响应依旧慢。

3.担心是有什么报错导致慢,于是艰难地开启了debug模式(由于用了pymysql所以开启debug模式也会有个报错),开启之后Django反应慢但没有任何报错,绝望~

4.都说用uwsgi中间件部署Django能加快响应速度,尝试之,没用。

扫描二维码关注公众号,回复: 11260108 查看本文章

5.作为运维人员的思路来了-整个链路监控吧,看看哪个环节慢了。在网上找到了django性能监控工具django-silk,装上之后发现只能看到请求耗时、sql查询耗时,sql查询耗时就几ms,也不慢啊,哭死!

6.是不是模板渲染或者代码有问题导致慢呢?

views.py中新建一个方法,不做任何处理,直接返回一个字符串,依旧慢!

7.从客户端发出请求到views.py处理计算这个过程很慢?

views.py的处理函数中增加print('test'),在浏览器中刷新网页后,查看Django输出,请求后要15s才能看到打印test。

8.客户端到服务器网络慢?

服务器上新建一个空白的Django项目,运行在相同的端口上,反应正常,网络没问题。

9.从Django接受到请求到views.py进行逻辑处理中间这个过程很慢!中间经过了django中间件middleware的处理,中间件导致的慢?

依次注释掉能注释的中间件,然后刷请求看浏览器发出请求到Django输出test的延时。

发现注释掉一个自定义的中间件后,Django很快就能输出test(看到了希望)。但是正常业务处理方法响应依旧慢。

10.自定义中间做了什么,怎么会耗费这么长时间?

查看中间件代码,发现每次请求进来Django进来以后,都要查询数据库,判断当前的url路径是否需要进行认证。

但这也是一次简单的数据库查询而已啊,为什么会这么慢,而且前面django-silk中也显示数据库查询响应很快?

有一点可以肯定的是Django查数据库这个动作耗费了大量的时间

11.既然查询数据库这个过程慢,那抓个到数据库的包看一下?

一顿操作后发现,当接收到请求后服务器会给数据库发一点数据,然后过了10多s后又发了一堆数据,等这一堆数据打传输完后浏览器上网页就返回了,这肯定跟响应慢有联系!深挖!

linux上抓包保存到文件,下载到windows上用wireshark分析发现:当Django收到用户请求后,会主动与数据库主机进行tcp连接,三次握手很快就成功了,然后等待了15s才收到MySQL的greet信息,才进查询。这说明服务器很快就与数据库主机建立了连接,但mysql应用等了15s才响应。此处不理解的,可以详细看一下MySQL协议。

12.由于公司的DB是由DBA负责的,而且现在也是周末,所以暂时没办法继续深挖DB原因。接下来怎么办呢,怎么解决Django响应慢的问题?

在服务器上继续抓包,想对比一下主机上其他应用查询MySQL有什么差异,发现其他应用连接MySQL时一样会有5s的延时。在分析包的过程中发现别的应用会发送ping这样的请求,咦,这不是心跳包吗?别的应用是不是有会话保持啥的?所以没看出来响应慢?

13.给Django也设置一下数据库长连接会话保持试一下?

百度上关于这块的文章都比较老了,都是通过sqlalchemy的连接池管理可以保持数据库的长连接和复用,要改源码操作起来比较麻烦。而且都是Django 1.4时代的解决办法了,现在都Django2.2了,官方有没有提供长连接的机制支持呢?百度和查官方文档后发现配置数据库连接信息时有个可选参数叫“CONN_MAX_AGE”,默认情况下值为0,即数据库查询连接用完之后就释放掉了,新的查询又要重新建立一次连接。

将参数设置为2个小时,再次实验。启动Django后,第一次请求还是很慢,但后面的请求就加快了,问题得到了临时解决!

Todo: 至于数据库为什么要15s才响应连接,这个上班后再找DBA了解具体原因。

寄语:这次问题排查真的很艰难,尝试了各种办法,花了很多时间,终于通过抓包找到了相关的原因。讲真,通过这次问题的排查让我有增加了很多Django的知识!希望能对你有所帮助。

猜你喜欢

转载自www.cnblogs.com/wurijie/p/12950633.html