Py学习  »  Django

使用DTrace和cProfile分析Django性能

Python程序员 • 4 年前 • 733 次点击  

Django是一个非常棒的框架,相当重要的原因是它包含了快速创建web应用程序所需的一切。但是开发者不应该是唯一的受益者。这个应用程序对用户来说也应该更快。


官方文档中有一章是关于性能和优化的,其中提供了很好的建议。在本文中,我将在此基础上展示我过去用来减少页面加载时间的工具和方法。


测量 & 收集数据


性能基准测试和概要分析对于任何优化工作都是必不可少的。盲目地应用优化可能会增加代码库的复杂性,甚至可能使情况变得更糟。


我们需要性能数据来了解应该关注哪些部分,并验证任何更改是否达到了预期的效果.


django-debug-toolbar


django-debug-toolbar很容易使用,并且有一个很好的界面。它可以显示每个SQL查询花费了多少时间,并有一个快速按钮可以获得该查询的EXPLAIN输出和其他一些有趣的细节。template-profiler是一个额外的面板,用于添加有关模板呈现过程的分析数据。

不过,django-debug-toolbar也有一些缺点。由于它集成到站点中的方式,所以只有在DEBUG = True的开发环境中使用它是有意义的。它本身也会带来巨大的性能损失。


DTrace


DTrace就没有这些限制。它可以用于生产服务,并提供比项目的python部分更多的细节。您可以深入了解数据库、python解释器、web服务器和操作系统,以获得每个地方时间花费的完整信息。


这将发生在CLI中,而不是漂亮的浏览器UI中。DTrace脚本是用类AWK语法编写的。在dtracetools包中还有一些有用的脚本。当您使用Joyent pkgsrc repos时,您可以使用一下代码来安装它:


这个包中有用的脚本之一是dtrace-mysql_query_monitor.d,它将显示所有的MySQL查询:


您也可以对PostgreSQL做同样的事情:


输出将会像这样:


在dtracetools包中有一些非常有用的dtrace-py_*脚本,可以帮助你深入了解python过程本身。例如dtrace-py_cputime.d将显示一个函数的调用次数以及包含和不包含CPU的时间:

    

在本例中,我们看到在正则表达式相关的东西上花费了一些时间,可能与URL路由有关。


cProfile


标准的python库附带了cProfile,它将收集函数调用的精确时间。我们可以将它与django test client一起使用来进行自动化性能测试。


尽可能多地自动化性能数据收集步骤有助于快速迭代。在最近的一个项目中,我创建了一个专用的manage.py命令来分析最重要的URL。它看起来像这样:

我们不但可以打印统计数据,还可以使用pr.dump_stats(fn)将统计数据保存到磁盘。这允许我们使用flameprof进行进一步处理来创建火焰图。


%timeit


另一个来自标准库的方便实用程序是timeit。你会经常发现这样的例子:


这在对小型语句进行实验是很有用。


为了更进一步,我建议您安装IPython,它会将Django manage.py shell 转换成一个非常强大的开发环境。


除了tab-补全和其他上千个功能外,你还会拥有%timeit魔法。


优化


一旦你知道你的项目中哪些部分是最慢的,你就可以开始改进这些部分。通常大部分时间是花在数据库查询上,然后是模板呈现。


虽然每个项目可能需要不同的优化,但也有一些常见的模式。


预加载相关的对象


当您在模板中显示一个对象列表并访问一个相关对象的某个字段时,将触发一个额外的数据库查询。这些耗时很容易地叠加起来,并导致针对一个请求的大量查询。


当您知道您将需要哪些相关字段时,您就可以告诉Django以更有效的方式去获得这些字段。两个重要的方法是select_related()和prefetch_related()。


select_related()通过使用一个SQL JOIN prefetch_related()为每个查找创建一个查询。它们易于使用,几乎不需要对现有代码进行任何修改,并且可以带来巨大的改进。


索引


另一个容易应用的性能调整是确保您有正确的数据库索引。无论您何时使用一个字段进行filter,在某些情况下是进行order_by,您都应该考虑是否需要索引。创建索引与向模型字段添加db_index = True一样简单,然后创建并运行结果迁移。确保使用SQL EXPLAIN去验证改进。


缓存


缓存是一个很大的主题,有很多方法可以通过缓存来提高django的性能。根据环境和性能特征,使用缓存的位置、持续时间和层将不同。


django cache 框架是在各个层上利用Memcached的一种简单方法。@cached_property装饰器通常对胖模型方法很有帮助。


>>> 今日签到口令:8wgf <<<


预计算


有些计算对于一个HTTP请求的时间预算来说太长了。在这些情况下,我发现在后台进程中预先计算所需的数据是很有用的。这可以通过像Celery这样的任务队列来完成,也可以通过一个manage.py命令来降低复杂性,该命令可以作为一个服务或作为一个定时任务长期运行。


Django之外


除了这些常见的情况外,还有许多进一步优化web项目的方法。通过反规范化更改数据库模式可能会改进一些查询。其他技术将在很大程度上取决于项目的环境。


通常也有很多机会去优化堆栈和下面的东西。从浏览器中测量性能数据,在Django中花费的时间只会越来越少。有了这些新数据,你就可以开始处理DOM渲染、CSS和JS,减少图像请求大小或更好的网络路由。


查看更低级别的改进也能带来巨大的好处。即使是低级别的小改进也会导致性能的提高,这仅仅是因为这些部分运行得太频繁了。


最近的一个例子是,通过改变python解释器的编译方式,每个请求获得了约120ms的提升。我测试的cpython版本中已经启用了retpoline缓解。这是一个孤立的内部服务,而威胁模型是不需要这个服务的。因此,仅通过不使用-mindirect-branch=thunk-inline -mfunction-return=thunk-inline -mindirect-branch-register进行编译就可以极大地提高性能。


如果您的web项目需要进行一些性能优化,请随时联系我们!


英文原文:https://wiedi.frubar.net/blog/2019/11/18/django-performance/ 
译者:Nothing
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/50918
 
733 次点击