Nginx + Gunicorn + Django Stack 上的站点缓慢故障排除

Posted

技术标签:

【中文标题】Nginx + Gunicorn + Django Stack 上的站点缓慢故障排除【英文标题】:Troubleshooting Site Slowness on a Nginx + Gunicorn + Django Stack 【发布时间】:2012-05-11 04:55:24 【问题描述】:

我遇到的问题

我遇到了一些网站需要很长时间才能加载的问题(“长时间”是指最多 16 秒)。有时它们可​​能会完全超时,从而产生 nginx 504 错误。通常,当一个站点超时时,我可以再次重新加载该站点,它会很快加载。我遇到问题的网站的流量非常低。我正在通过加载 Django 管理索引页面来测试该站点,以尝试消除由于代码不佳而可能导致的任何缓慢。还应注意,此特定站点仅使用 Django 管理员,因为它是仅供员工使用的 Intranet 类型站点。

主机设置

我托管的所有网站都位于两台 Rackspace 云服务器上。第一个服务器是我的应用服务器,它有 1024 MB 的 RAM,我的第二个服务器是我的数据库服务器,它有 2048 MB 的 RAM。应用服务器使用 Nginx 为每个站点提供服务,Nginx 提供所有静态文件并将其他所有内容代理给每个站点的 Django Gunicorn 工作人员。

查看数据库服务器的 RAM 和 CPU 负载时​​,似乎数据库服务器上的一切都很好。

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1999       1597        402          0        200       1007
-/+ buffers/cache:        389       1610
Swap:         4094          0       4094


Top shows a CPU load average of: 0.00, 0.01, 0.05

为了尝试解决正在发生的事情,我写了一个简短的 script,它会打印出应用服务器上的内存使用情况。

匿名网站域的打印示例:

Celery:     23 MB
Gunicorn:  566 MB
Nginx:       8 MB
Redis:     684 KB
Other:      73 MB

             total       used       free     shared    buffers     cached
Mem:           993        906         87          0         19         62
-/+ buffers/cache:        824        169
Swap:         2047        828       1218

Gunicorn memory usage by webste:
site01.example.com    31 MB
site02.example.com    19 MB
site03.example.com     7 MB
site04.example.com     9 MB
site05.example.com    47 MB
site06.example.com    25 MB
site07.example.com    14 MB
site08.example.com    18 MB
site09.example.com    27 MB
site10.example.com    15 MB
site11.example.com    14 MB
site12.example.com     7 MB
site13.example.com    18 MB
site14.example.com    18 MB
site15.example.com    10 MB
site16.example.com    25 MB
site17.example.com    13 MB
site18.example.com    18 MB
site19.example.com    37 MB
site20.example.com    30 MB
site21.example.com    23 MB
site22.example.com    28 MB
site23.example.com    80 MB
site24.example.com    15 MB
site25.example.com     5 MB

Gunicorn 配置文件示例:

pidfile = '/var/run/gunicorn_example.com.pid'
proc_name = 'example.com'
workers = 1
bind = 'unix:/tmp/gunicorn_example.com.sock'

Nginx 配置示例:

upstream example_app_server 
    server unix:/tmp/gunicorn_example.com.sock fail_timeout=0;


server 

    listen       80;
    server_name  example.com;
    access_log   /var/log/nginx/example.com.access.log;
    error_log    /var/log/nginx/example.com.error.log;

    location = /favicon.ico 
        return  404;
    

    location  /static/ 
        root  /srv/sites/example/;
    

    location  /media/ 
        root  /srv/sites/example/;
    

    location  / 
        proxy_pass            http://example_app_server;
        proxy_redirect        off;
        proxy_set_header      Host             $host;
        proxy_set_header      X-Real-IP        $remote_addr;
        proxy_set_header      X-Forwarded-For  $proxy_add_x_forwarded_for;
        client_max_body_size  10m;
    


如您所见,有很多内存被交换,所以为了解决我的问题,我升级了应用服务器上的 ram,这完全解决了网站的缓慢问题。尽管我能够解决这个问题,但我花费的时间比我想要的要长得多,而且我仍然觉得我基本上是在猜测导致网站运行缓慢的原因。这一切都引出了我的问题……

问题

    您如何判断低流量站点上的站点缓慢不是由于站点不活动导致站点变为不活动,进而导致 Gunicorn 在站点变为不活动后必须再次加载站点?是否有防止网站处于非活动状态的设置? 似乎我的某些网站占用了太多内存。我可以使用哪些工具来减少站点使用的内存量?我应该使用一些 Python 分析工具吗? 有哪些工具和步骤可以用来确定瓶颈发生在堆栈的哪个级别? 确定是您的 Gunicorn 进程被交换还是其他进程被交换的最佳方法是什么? 我托管的大多数网站都没有大量流量,因此我只使用了一名 Gunicorn 工作人员。是否有更科学的方法来确定和调整您在网站上拥有多少 Gunicorn 工人? 在同一台服务器上托管多个站点时,是否可以通过配置来减少内存占用?

【问题讨论】:

仅供参考,我发现使用Munin 是查看问题的好工具。 我也有人推荐blitz.io,但我还没有机会使用它。 【参考方案1】:

在只有 1GB RAM 的服务器上托管大量网站。您的内存利用率接近 100%,并且您拥有的数字可能是“备用”数字。在处理请求的过程中,每个进程的 RAM 使用量可以并且将会激增。马上,您需要为此实例添加更多 RAM,并且最好将一些站点移到另一台服务器上。

关于你的问题:

    您从哪里得知网站变得“不活跃”而 Gunicorn 必须再次加载该网站?那是垃圾。只要 Gunicorn 进程正在运行(即没有被手动终止或因站点上的错误而终止),它就会保持完全初始化并准备就绪,无论是一个小时还是一个月。

    你在这里砍树叶,而根没有受到影响。每个 Gunicorn 进程的内存使用情况并没有什么异常。它需要 RAM 才能运行。您的问题是试图在功率严重不足的服务器上运行太多。没有优化可以在这里拯救你。您需要更多 RAM 或更多服务器。可能两者兼而有之。

    不需要。同样,问题已经确定。事实上,您发布的数字非常清楚。

    无法可靠地知道哪些进程正在被交换。它每秒都在变化,取决于哪些正在积极运行并需要更多 RAM,哪些不活跃或根本不活跃。当您的服务器资源如此紧张时,它会花费一半的时间来确定接下来要处理哪个进程,尤其是当它们都处于活动状态并争夺资源时。

    是的。 Gunicorn 推荐 2*cores+1。所以在双核系统上,是 5;在四核上,9。但是,您无法在这个系统上为每个站点运行 5 个工作人员。您甚至无法可靠地为每个工作人员运行 1 个工作人员。

    这取决于“事物”。但是,当多个站点托管在同一台服务器上时,这些服务器在规范方面是野兽。在像你这样的小型 VPS 实例上,尤其是只有 1GB 的 RAM,一个站点几乎是你的极限。两个,也许吧。

【讨论】:

我猜你错过了这个......"Even though I was able to fix the issue, it took me a lot longer than I would like and I still feel like I was basically guessing at what was causing the site slowness. All this leads me to my questions..."一般来说,我的问题是试图获取人们在解决 Django 堆栈上的缓慢问题时使用的步骤和工具列表。关于您对 5 的回答,我认为 Gunicorn 的建议是矫枉过正。我托管的网站在一名工作人员的情况下运行良好,这取决于您的流量。我在寻找更科学的东西。【参考方案2】:

1) 不确定您所说的不活动是什么意思?如,被 nginx 禁用?还是工作太慢?

2 和 3) django-debug-toolbar 和 django-debug-logging 将是一个很好的起点。如果这没有帮助,是时候转向服务器级别的分析,看看是哪些进程导致了问题。

4) 使用顶部:How to find out which processes are swapping in linux?

5) 是的 - 基准测试。选择一个基准测试工具(例如 apachebench)并针对您当前的配置运行测试。调整一些东西。再次运行测试。重复直到你的性能问题消失!为获得最佳效果,请使用与您的实时流量相似的流量(在 URL 分配、GET/POST 等方面)。

6) 是的,在 nginx 和应用程序级别。通过分析每个站点并提高其内存使用率(参见 2),您可能会获得最大的收益。

【讨论】:

1) 响应缓慢。就我而言,这是因为工人被调换了。 2) 我会这样做,但这在实时服务器上不实用?【参考方案3】:

关于:

关于你对 5 的回答,我相信 Gunicorn 推荐的是 矫枉过正。

我最近对工人数量进行了一些临时测试,发现假设您有足够的 RAM,那么 2*cores+1 的经验法则非常准确。我发现每秒请求数几乎呈线性增长,直到我接近这个数字,然后随着操作系统开始抖动而下降。

由于结果很大程度上取决于工作负载,因此请尝试不同的值并查看您的性能峰值在哪里。

【讨论】:

这就是我所说的,除非您的网站获得大量流量,否则这是矫枉过正的。我在所有站点上都有一名工作人员,他们的响应时间很快。按照 Gunicorn 的建议,需要 3 或 4 倍的 Ram。如果您的网站没有流量,那么为什么要浪费 Ram。我只是希望有一种更科学的方法来调整您的工人(即,如果您获得 X 次综合浏览量,请使用 X 个工人)。 @Brent “为什么要浪费内存”没有多大意义。如果您有一台服务器正在运行,请从它那里获得最大的性能(显然有安全边界)! @Brent if you get X pageviews use X workers 是科学的相反。科学涉及实验/测量,而不是简化的经验法则。 @glarrain 是的,不使用内存是在浪费内存。

以上是关于Nginx + Gunicorn + Django Stack 上的站点缓慢故障排除的主要内容,如果未能解决你的问题,请参考以下文章

Django-Gunicorn-Nginx 部署没有通过 Nginx

Django/gunicorn/nginx: 403 禁止

Django、Nginx、Gunicorn 和 AngularJS 应用程序结构

Nginx Django 和 Gunicorn。 Gunicorn 袜子文件丢失?

为啥 nginx 不会用 django 和 gunicorn 显示静态内容?

Django,Nginx,Gunicorn。 Ubuntu 16.04 错误