如何扩展 Django:超越基础

开始的


你已经部署了Django到你的Droplet,生活很好。随着网站的流量增加,你遇到了一些性能问题,但你已经找到瓶颈(https://www.digitalocean.com/community/articles/how-to-scale-django-finding-the-bottleneck)并修复了它。

这个文章是写在假设你正在使用Ubuntu 12.04,但原则与任何版本的Linux工作。

如果您正在使用Apache,那么您应该遵循 优化您的Web服务器的说明。

隐藏一切


如果你创建了一个 CMS 来管理你的网站,那么你很可能可以容忍非常激进的缓存。在这种情况下,我最喜欢的工具是Varnish,一个前端缓存,坐在Apache或Nginx前面。

缺点是,Varnish,除非您仔细配置,否则会缓存您的整个网站. 如果您有动态内容,例如,如果您的网站更像是一个应用程序,Varnish可能会引起很多麻烦。 假设用户A访问网站并将项目添加到他们的购物车中。

另一个缺点是,Django默认情况下试图强迫上游缓存来缓存内容,这导致了一些战斗,最终以不稳定的行为结束。

但我有一个好消息:Django有自己的缓存框架(https://docs.djangoproject.com/en/1.6/topics/cache/),它会给你两件事。

它将使您的应用程序更易于缓存,以便它与Varnish玩得很好(如果您选择使用它) 2它会让你控制网站的哪些部分被缓存

如果你正在使用一个较小的滴滴,我建议使用数据库缓存. 它很容易启动,避免需要运行另一个服务器流程. 如果你有足够的RAM memcached提供了一个很好的缓存后端. 本文将展示基于数据库的缓存。

浏览上面的链接文档,了解很多优秀的细节,但这里是你需要做的事情来开始。

在这种情况下,我们的表被称为cache_table:

1python manage.py createcachetable cache_table

现在编辑您的 settings.py 文件并通过添加这些行来配置缓存:

1CACHES = {
2    'default': {
3        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
4        'LOCATION': 'cache_table',
5    }
6}

您可以配置其他配置选项,请参阅 文档。我特别会检查 TIMEOUT 和 CULL_FREQUENCY。

现在你需要决定什么要缓存. 如果你只是想让你的网站在Varnish中更好地工作,然后检查 每站点缓存配置. 然而,这并不太令人兴奋,所以让我们挖掘每站点缓存。

假設您有一個購物車產品頁面,它很少改變,並且不非常動態. 您有一個名為「product_detail(request, product_id)」的視圖,這將是完美的缓存。

您可以使用一个简单的装饰程序来启用缓存:

1from django.views.decorators.cache import cache_page
2
3@cache_page(60 * 60)
4def product_detail(request, product_id):
5    ...

这将允许该视图在60分钟(60秒 * 60分钟)内缓存。

再次,我想引用 docs for some excellent tips。一个特别强大的功能是 variy based on headers。如果你有一个网站,它被翻译成多种语言,或你显示不同的内容基于浏览器版本,这可以是一个很大的帮助。

那么,经常变化的内容呢?


如果你有一个半动态的网站,例如你的应用程序收到大量的评论或数据被频繁更新,你可能会担心使用缓存。

首先识别所有可以被攻击性地缓存的视图,然后缓存它们。

其次,确定你可以容忍某人看到过时内容的延迟有多长时间,例如,一个具有活跃评论的网站可能会容忍1到5分钟的延迟。

你会感到惊讶 - 即使是10秒的缓存时间也可能非常有帮助. 在许多情况下,突然过载的繁忙网站通常会受到某个特定页面的流量袭击。

如果 10,000 人在一分钟内访问您的网站上的页面,那么当所有这些数据库查询同时运行时,您的服务器就会融化. 如果您设置了 10 秒的缓存,则意味着页面每分钟只会再生 6 次,无论有多少人要求它。

使用会话数据的电子商务网站和网站必须非常小心。 检查 variy标题选项,看看缓存是否可以在您的情况下工作。

网站有时会将所有HTML页面作为静态内容服务,并使用Ajax加载每位用户的会话信息。在电子商务网站的情况下,用户通常不会注意到他们的购物车数值需要5秒钟才能加载,只要他们可以正常浏览其他页面。

提供静态内容


Django 的内置开发服务器很高兴地提供静态内容. 经常,我看到 Django 网站配置用于生产使用,而静态内容由 Django 提供。

您唯一应该做到这一点的时机是,如果您需要控制对内容的访问,但即使如此,还可以考虑其他方法。

  • 动态生成的CSS - 不,请使用构建工具,如 Grunt或Less,在部署之前构建您的CSS。如果需要在服务器上定期生成,那么请使用 背景任务
  • 身份验证用户访问 - 是的,您可能需要使用Django
  • 其他一切 - 不,让我们与您的Web服务器配置静态内容托管

在我得到它之前,我不得不阅读 静态文件的文档几次,我认为你应该自己阅读它,但如果你也挣扎了,这里有一个你可以使用的场景:

在本地开发机器上,在settings.py中,添加这样的行:

1STATIC_ROOT = os.path.join(BASE_DIR, "static")

然后运行 manage.py 命令如下:

1python manage.py collectstatic

你现在应该在你的项目根中看到一个名为静态的文件夹,在里面你会看到很多静态文件,如CSS和JavaScript。

要使用这些文件,您需要配置 Django,以便它知道在哪里寻找它们. 在您的 settings.py 文件夹中,您需要这样的配置选项:

1STATICFILES_DIRS = (
2    os.path.join(BASE_DIR, "static"),
3)

现在,如果您运行开发者服务器并访问管理区域并查看任何页面的来源,您应该看到CSS文件正在从/static/admin/css/服务。

当您部署应用程序时,您现在可以向 Apache 或 Nginx 指向以 /static/ 开头的文件,直接指向这些文件。

如果你的应用部署到 /srv/myapp/,因此你有一个名为 `/srv/myapp/static/admin/css/base.css’的文件,那么你可以这样配置你的Web服务器:

阿帕奇:

1Alias /static/ "/srv/myapp/static/"

天津:**

1server {
2    ...
3    location /static/ {
4        alias /srv/myapp/static/;
5    }
6}

在这两种情况下,你只是将 /static / URL 指向硬盘上的确切位置,在那里找到文件. Apache 和 Nginx 可以比 Django 更快地服务这些。

使用UWSGI


如果我想快速发布一个网站,我会使用Apache的mod_wsgi. 如果我想要最好的性能,我会使用uWSGI. 如果你想知道如何发音,那就是你威士忌

uWSGI 是一个服务器流程,在 Web 服务器之外运行您的应用程序. 对于 Apache,您需要安装以下软件包:

1sudo apt-get install uwsgi uwsgi-plugin-python uwsgi-plugin-cgi

如果您正在使用 Apache 作为 Web 服务器,则还可以安装:

1sudo apt-get install libapache2-mod-uwsgi

一旦你做到了,你会注意到你现在有两个新的配置文件夹: /etc/uwsgi/apps-available/etc/uwsgi/apps-enabled,就像你看到你的虚拟主机配置与Apache或Nginx一样。

当您想创建一个新的应用程序时,您将配置文件放入 /etc/uwsgi/apps-available,然后从 app-enabled 创建一个同步链接。

假设您已经创建了一个名为 newproject 的项目,并将其放置在 /srv/newproject. 正如 Django 项目的典型情况下,在 /srv/newproject/newproject/settings.py 有一个 settings.py 文件。

创建一个名为 `/etc/uwsgi/apps-available/newproject.ini 的文件,然后编辑它看起来像这样:

1[uwsgi]
2touch-reload = /tmp/newproject
3socket = 127.0.0.1:3031
4workers = 2
5chdir = /srv/newproject
6env = DJANGO_SETTINGS_MODULE=newproject.settings
7module = django.core.handlers.wsgi:WSGIHander()

现在创建一个名为 /tmp/newproject 的空格文件:

1touch /tmp/newproject

您必须通过将文件链接到app-enabled来激活应用程序:

1sudo ln -s /etc/uwsgi/apps-available/newproject.ini /etc/uwsgi/apps-enabled/newproject.ini

然后重新启动 uWSGI:

1sudo service uwsgi restart

如果你检查ps ax的输出,你应该看到一些与你的应用程序相关的运行过程。

请注意,如果您在同一服务器上运行了多个应用程序,则需要为每个应用程序的接口使用不同的端口。

此外,如果您更新您的应用程序,您应该简单地触摸 /tmp/newproject 文件,而 uWSGI 将重新加载。

您可以随时查看/var/log/uwsgi/app/newproject.log以查看信息消息和错误。

Apache 配置


如果你正在使用mod_wsgi,现在是真相的时刻,你应该禁用mod_wsgi并启用mod_uwsgi,这可能会导致错误,所以在测试服务器上执行此操作,直到你找到正确的配置。

1sudo a2dismod wsgi
2sudo a2enmod uwsgi

现在更新您的应用程序的配置. 在您的 apache 配置中,您可能有这样的行:

1WSGIScriptAlias / /srv/newproject/newproject.wsgi

你会更新到这样一个:

1SetHandler uwsgi-handler
2uWSGISocket 127.0.0.1:3031

现在重新加载您的 Apache 配置:

1sudo service apache2 reload

Nginx 配置


在您的服务器配置中,您需要将现有的 wsgi 指令替换为以下:

1uwsgi_pass 127.0.0.1:3031;
2include uwsgi_params;
3uwsgi_param UWSGI_SCHEME $scheme;

很简单!

UWSGI 好处


使用uWSGI的一个美好方面是,你可以限制你的应用程序在内存中运行的次数。通常会有一个家长过程,如果你使用了上面的共享配置,则有2名工人。如果你需要更多的工人,你可以简单地编辑应用程序的ini文件并增加工人的数量。然后用sudo service uwsgi reload重新加载uWSGI来更新更改。

在增加进程数量之前,请考虑您使用的服务器内存量。如果您在运行mod_wsgi之前,您应该看到内存使用量下降。不要观察 uWSGI 工人的大小。

最大化使用


在您的应用程序加热并使用一段时间后,检查您的服务器的内存利用率。

使用免费 -m命令来查看缓存/缓存与应用程序使用的内存量。 关键值是免费列中的顶号。

如果你发现你有 RAM 可以储存,你的网站是慢的,然后挖掘是什么被不足使用。

通常情况下,你会发现流程正在等待MySQL。你可能需要向数据库分配更多的系统内存,这是非常常见的,因为MySQL的默认配置非常少使用RAM。

还可能没有足够的RAM分配到磁盘缓存中吗?你有没有不必要的流程占用内存?默认情况下,Linux会分配尽可能多的RAM到磁盘缓存中,当应用程序需要它时不情愿地放弃它。

在理想情况下,这种情况从不发生在内存限制的VPS环境中,所有仅可读的资产都将在缓存中缓存,因此摆脱不必要的背景过程。

包装上


您已经学习了一些缓存技术,包括使用 Varnish 缓存整个网站或每视图控制缓存设置。

您已经确保静态文件正在与Web服务器提供服务,而不是Django。

你已经学会了如何使用uWSGI来提高你的Django应用程序的性能,通过从Web服务器中运行它(顺便说一句,感谢Ricardo Pascal他的 优秀的Apache/uWSGI文档)

最后,您了解了如何将尽可能多的内存分配到您的服务器应用程序中,以最大限度地利用。

Submitted by: Matthew Nuzum
comments powered by Disqus