跳转到主要内容

Django框架的丝般顺滑性能分析

项目描述

Silk

GitHub Actions GitHub Actions PyPI Download PyPI Python Versions Supported Django versions Jazzband

Silk是一个为Django框架提供的实时性能分析工具。Silk拦截并存储HTTP请求和数据库查询,然后将它们以用户界面形式呈现,以便进一步检查。

内容

要求

Silk已在以下环境中测试过:

  • Django: 3.2, 4.2, 5.0, 5.1
  • Python: 3.8, 3.9, 3.10, 3.11, 3.12

安装

通过pip安装到virtualenv

pip install django-silk

settings.py中添加以下内容

MIDDLEWARE = [
    ...
    'silk.middleware.SilkyMiddleware',
    ...
]

INSTALLED_APPS = (
    ...
    'silk'
)

注意:中间件的位置很敏感。如果在silk.middleware.SilkyMiddleware之前的中间件在process_request中返回,则SilkyMiddleware将永远不会有机会执行。因此,您必须确保放置在之前的任何中间件都不会从process_request返回任何内容。有关此信息的更多信息,请参阅Django文档

注意:如果您正在使用django.middleware.gzip.GZipMiddleware,请将其放置在silk.middleware.SilkyMiddleware之前,否则您将遇到编码错误。

如果您想使用自定义中间件,例如您开发了silk.middleware.SilkyMiddleware的子类,那么您可以使用以下设置组合

# Specify the path where is the custom middleware placed
SILKY_MIDDLEWARE_CLASS = 'path.to.your.middleware.MyCustomSilkyMiddleware'

# Use this variable in list of middleware
MIDDLEWARE = [
    ...
    SILKY_MIDDLEWARE_CLASS,
    ...
]

要启用对用户界面的访问,请将以下内容添加到您的urls.py

urlpatterns += [path('silk/', include('silk.urls', namespace='silk'))]

在运行迁移之前

python manage.py migrate

python manage.py collectstatic

Silk将自动开始拦截请求,并且您可以继续添加分析(如果需要的话)。UI可以通过/silk/访问

替代安装

通过GitHub标签

pip install https://github.com/jazzband/silk/archive/<version>.tar.gz

您可以使用以下命令从master安装,但请注意,master中的版本可能不会适用于在要求中指定的所有版本

pip install -e git+https://github.com/jazzband/django-silk.git#egg=django-silk

功能

Silk主要由以下部分组成:

  • 拦截请求/响应的中间件
  • 对SQL执行进行封装,以分析数据库查询
  • 用于手动或动态分析代码块和函数的上下文管理器/装饰器。
  • 用于检查和可视化上述内容的用户界面。

请求检查

Silk中间件会拦截并存储在配置的数据库中的请求和响应。然后可以通过请求概述使用Silk的UI过滤和检查这些请求

它记录如下内容:

  • 耗时
  • 查询数
  • 查询耗时
  • 请求/响应头
  • 请求/响应体

等等。

通过单击相关的请求还可以获得每个请求的更多详细信息

SQL检查

Silk还会拦截由每个请求生成的SQL查询。我们可以总结有关涉及到的表、连接数和执行时间(可以通过单击列标题对表进行排序)的内容

在深入堆栈跟踪以确定此请求的来源之前

分析

启用SILKY_PYTHON_PROFILER设置以使用Python内置的cProfile分析器。每个请求都将单独进行分析,分析器的输出将可在Silk UI的请求分析页面中找到。请注意,从Python 3.12开始,cProfile无法并发运行,因此Python 3.12及更高版本的django-silk在另一个分析器正在运行时将不会进行分析(即使是在另一个线程中的自己的分析器)。

SILKY_PYTHON_PROFILER = True

如果您想生成二进制.prof文件,请设置以下内容

SILKY_PYTHON_PROFILER_BINARY = True

启用时,将使用gprof2dotviz.js生成的图形可视化显示在分析详细页面中

可以使用自定义存储类来保存生成的二进制.prof文件

# For Django >= 4.2 and Django-Silk >= 5.1.0:
# See https://docs.django.ac.cn/en/5.0/ref/settings/#std-setting-STORAGES
STORAGES = {
    'SILKY_STORAGE': {
        'BACKEND': 'path.to.StorageClass',
    },
    # ...
}

# For Django < 4.2 or Django-Silk < 5.1.0
SILKY_STORAGE_CLASS = 'path.to.StorageClass'

默认存储类是silk.storage.ProfilerResultStorage,当使用它时,您可以指定您选择的路径。您必须确保指定的目录存在。

# If this is not set, MEDIA_ROOT will be used.
SILKY_PYTHON_PROFILER_RESULT_PATH = '/path/to/profiles/'

每个请求都将有一个下载按钮,下载二进制.prof文件。此文件可用于使用snakeviz或其他cProfile工具进行进一步分析

要检索生成特定配置文件端点的方法,可以在文件名中添加请求路径的占位符,如下所示

SILKY_PYTHON_PROFILER_EXTENDED_FILE_NAME = True

Silk 还可以用于分析特定的代码块或函数。为此,它提供了一个装饰器和上下文管理器。

例如

from silk.profiling.profiler import silk_profile


@silk_profile(name='View Blog Post')
def post(request, post_id):
    p = Post.objects.get(pk=post_id)
    return render(request, 'post.html', {
        'post': p
    })

每当查看博客文章时,我们都会在 Silk UI 中获得一个条目

Silk 分析不仅提供执行时间,而且还以与请求相同的方式收集块内执行的 SQL 查询

装饰器

Silk 装饰器可以应用于函数和方法

from silk.profiling.profiler import silk_profile


# Profile a view function
@silk_profile(name='View Blog Post')
def post(request, post_id):
    p = Post.objects.get(pk=post_id)
    return render(request, 'post.html', {
        'post': p
    })


# Profile a method in a view class
class MyView(View):
    @silk_profile(name='View Blog Post')
    def get(self, request):
        p = Post.objects.get(pk=post_id)
        return render(request, 'post.html', {
            'post': p
        })

上下文管理器

使用上下文管理器意味着我们可以向名称中添加额外的上下文,这对于缩小缓慢到特定数据库记录非常有用。

def post(request, post_id):
    with silk_profile(name='View Blog Post #%d' % self.pk):
        p = Post.objects.get(pk=post_id)
        return render(request, 'post.html', {
            'post': p
        })

动态分析

Silk 的一个更有趣的特性是动态分析。例如,如果我们只想分析我们只有只读访问权限的依赖项中的函数(例如,由 root 拥有的系统 Python 库),我们可以在 settings.py 中添加以下内容以在运行时应用装饰器

SILKY_DYNAMIC_PROFILING = [{
    'module': 'path.to.module',
    'function': 'MyClass.bar'
}]

这大致相当于

class MyClass:
    @silk_profile()
    def bar(self):
        pass

以下总结了可能的情况

"""
Dynamic function decorator
"""

SILKY_DYNAMIC_PROFILING = [{
    'module': 'path.to.module',
    'function': 'foo'
}]

# ... is roughly equivalent to
@silk_profile()
def foo():
    pass

"""
Dynamic method decorator
"""

SILKY_DYNAMIC_PROFILING = [{
    'module': 'path.to.module',
    'function': 'MyClass.bar'
}]

# ... is roughly equivalent to
class MyClass:

    @silk_profile()
    def bar(self):
        pass

"""
Dynamic code block profiling
"""

SILKY_DYNAMIC_PROFILING = [{
    'module': 'path.to.module',
    'function': 'foo',
    # Line numbers are relative to the function as opposed to the file in which it resides
    'start_line': 1,
    'end_line': 2,
    'name': 'Slow Foo'
}]

# ... is roughly equivalent to
def foo():
    with silk_profile(name='Slow Foo'):
        print (1)
        print (2)
    print(3)
    print(4)

请注意,动态分析的行为与 Python 模拟框架相似,即我们修改函数本身,例如

""" my.module """
from another.module import foo

# ...do some stuff
foo()
# ...do some other stuff

,我们会通过动态装饰 my.module.foo 来分析 foo,而不是 another.module.foo

SILKY_DYNAMIC_PROFILING = [{
    'module': 'my.module',
    'function': 'foo'
}]

如果我们要将动态分析应用于在已导入后导入的函数源模块 another.module.foo,则不会触发分析。

分析的自定义逻辑

有时您可能希望动态控制分析器何时运行。您可以为何时启用分析器编写自己的逻辑。为此,请将以下内容添加到您的 settings.py

此设置与 SILKY_PYTHON_PROFILER 相互排斥,并且如果存在,将覆盖它。它将与 SILKY_DYNAMIC_PROFILING 一起使用。

def my_custom_logic(request):
    return 'profile_requests' in request.session

SILKY_PYTHON_PROFILER_FUNC = my_custom_logic # profile only session has recording enabled.

您还可以使用一个 lambda 表达式。

# profile only session has recording enabled.
SILKY_PYTHON_PROFILER_FUNC = lambda request: 'profile_requests' in request.session

代码生成

Silk 当前为每个请求生成两段代码

这两段代码都旨在用于重新播放请求。可以使用 curl 命令通过命令行进行重播,也可以在 Django 单元测试或作为独立脚本中使用 Python 代码。

配置

身份验证/授权

默认情况下,任何人都可以通过转到 /silk/ 访问 Silk 用户界面。要启用您的 Django 身份验证后端,请在 settings.py 中添加以下内容

SILKY_AUTHENTICATION = True  # User must login
SILKY_AUTHORISATION = True  # User must have permissions

如果 SILKY_AUTHORISATION 设置为 True,则默认情况下 Silk 将只授权将 is_staff 属性设置为 True 的用户。

您可以使用以下内容在 settings.py 中自定义此设置

def my_custom_perms(user):
    return user.is_allowed_to_use_silk

SILKY_PERMISSIONS = my_custom_perms

您还可以使用一个 lambda 表达式。

SILKY_PERMISSIONS = lambda user: user.is_superuser

请求/响应体

默认情况下,Silk 会为每个请求保存请求和响应体,以便将来查看,无论大小如何。如果在生产中大量使用 Silk 且请求体很大,这可能会对空间/时间性能产生巨大影响。此行为可以通过以下选项进行配置

SILKY_MAX_REQUEST_BODY_SIZE = -1  # Silk takes anything <0 as no limit
SILKY_MAX_RESPONSE_BODY_SIZE = 1024  # If response body>1024 bytes, ignore

元性能分析

有时了解 Silk 对请求/响应时间的影响很有用。为此,请将以下内容添加到您的 settings.py

SILKY_META = True

Silk 将记录在每次请求结束时将所有内容保存到数据库所需的时间

请注意,在上面的屏幕截图中,这意味着请求耗时 29ms(其中 Django 耗时 22ms,Silk 耗时 7ms)

记录部分请求

在高负载网站上,可能只需记录部分请求。为此,请将以下内容添加到您的 settings.py

注意:此设置与 SILKY_INTERCEPT_FUNC 相互排斥。

SILKY_INTERCEPT_PERCENT = 50 # log only 50% of requests

记录请求的自定义逻辑

在高负载网站上,编写自己的逻辑来拦截请求可能也有帮助。为此,请将以下内容添加到您的 settings.py

注意:此设置与 SILKY_INTERCEPT_PERCENT 不兼容。

def my_custom_logic(request):
    return 'record_requests' in request.session

SILKY_INTERCEPT_FUNC = my_custom_logic # log only session has recording enabled.

您还可以使用一个 lambda 表达式。

# log only session has recording enabled.
SILKY_INTERCEPT_FUNC = lambda request: 'record_requests' in request.session

限制请求/响应数据

为了确保 Silk 能够回收旧请求/响应数据,可以设置一个配置变量来限制它存储的请求/响应行数。

SILKY_MAX_RECORDED_REQUESTS = 10**4

垃圾回收只针对请求的百分比运行,以减少开销。可以通过此配置进行调整

SILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT = 10

如果您想将 Silk 的垃圾回收与您的 web 服务器请求处理解耦,请设置 SILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT=0 并手动触发,例如在 cron 作业中

python manage.py silk_request_garbage_collect

启用查询分析

如果 dbms 支持,可以通过设置配置变量来执行带有分析功能的查询。

SILKY_ANALYZE_QUERIES = True

警告:此设置可能导致数据库执行相同的查询两次,具体取决于后端。例如,Postgres 中的 EXPLAIN ANALYZE 实际上会执行查询,这可能导致意外的数据更新。请谨慎设置此为 True。

如果您想为支持 dbms 的配置传递额外的参数(例如,VERBOSE、FORMAT JSON),可以按照以下方式进行。

SILKY_EXPLAIN_FLAGS = {'format':'JSON', 'costs': True}

在请求体上遮蔽敏感数据

默认情况下,Silk 会过滤包含以下键的值(它们不区分大小写)

SILKY_SENSITIVE_KEYS = {'username', 'api', 'token', 'key', 'secret', 'password', 'signature'}

但有时,您可能希望有自己的敏感关键词,那么上述配置可以修改

SILKY_SENSITIVE_KEYS = {'custom-password'}

清除记录的数据

管理命令会清除所有记录的数据

python manage.py silk_clear_request_log

贡献

Jazzband

这是一个 Jazzband 项目。通过贡献,您同意遵守 贡献者行为准则 并遵循 指南

开发环境

Silk 包含一个名为 project 的项目,可用于 silk 开发。它将 silk 代码链接,因此您可以在同一时间工作于示例 projectsilk 包。

为了设置本地开发,您首先需要安装测试 project 的所有依赖项。从 project 目录的根目录开始

pip install -r requirements.txt

您还需要安装 silk 的依赖项。从 git 仓库的根目录开始

pip install -e .

此时,您的虚拟环境应该拥有运行示例 projectsilk 所需的一切。

在运行之前,您必须设置 DB_ENGINEDB_NAME 环境变量

export DB_ENGINE=sqlite3
export DB_NAME=db.sqlite3

对于其他组合,请检查 tox.ini

现在从示例 project 的根目录应用迁移

python manage.py migrate

现在从示例 project 目录的根目录启动 django 服务器

python manage.py runserver

运行测试

cd project
python manage.py test

快乐的剖析!

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

django_silk-5.2.0.tar.gz (4.4 MB 查看哈希值)

上传时间 源代码

构建分发

django_silk-5.2.0-py3-none-any.whl (1.8 MB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面