【问题标题】:Debugging silent failure in Gunicorn/NGINX/Django在 Gunicorn/NGINX/Django 中调试静默失败
【发布时间】:2017-01-23 00:19:22
【问题描述】:

我正在使用 Gunicorn 运行一个 Django 项目。我使用 Nginx 作为反向代理。在大多数情况下,一切正常,但有一个 Django 视图导致 Gunicorn 静默失败。

问题的详细信息如下,但首先,这是导致问题的 Django 视图:

def jobs_all(request):
    if not request.user.is_superuser: raise Http404
    jobs = Job.objects.all().order_by('-date_created')
    return render(request, 'monitor/jobs_all.html', {
        'jobs': jobs,
    })

如果我将'jobs': jobs, 更改为'jobs': [],,它会起作用。所以我认为问题涉及将这些 QuerySet 结果传递给模板。

浏览器中显示的错误是 Nginx 的 502 Bad Gateway 错误。我的 Nginx 错误日志显示:

2017/01/22 05:17:25 [error] 22#0: *26 upstream prematurely closed connection while reading response header from upstream, client: 12.34.56.78, server: www.example.com, request: "GET /monitor/jobs/all/ HTTP/1.1", upstream: "http://127.0.0.1:8000/monitor/jobs/all/", host: "www.example.com", referrer: "https://www.example.com/monitor/"

好的,所以看起来 Gunicorn 正在超时或以某种方式关闭。但我不明白怎么做。错误发生在几秒钟内,这在我的 Nginx 和 Gunicorn 配置下应该不是问题。我没有看到任何其他错误消息。

这是我启动 Gunicorn 的命令:

$ /usr/local/bin/gunicorn -b 127.0.0.1:8000 --keep-alive 43200 -w 4 --log-level=DEBUG mydjangoproject.wsgi --timeout=43200

(在生产中,我通过使用 Supervisor 调用类似的命令来启动 Gunicorn,但使用不同的日志级别和日志文件路径。我检查了 Gunicorn 日志;他们对这个错误保持沉默。)

我的 Nginx 配置是:

server {
    listen 443 ssl;
    server_name www.example.com;
    access_log /dev/null;
    error_log /logs/nginx/nginx.error.log;

    ssl_certificate /code/ssl/ssl-bundle.crt;
    ssl_certificate_key /code/ssl/server.key;
    ssl_dhparam /code/ssl/dhparams.pem;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

    server_tokens off;

    if ($request_method !~ ^(GET|HEAD|POST)$ ) {
        return 405;
    }

    location /static/ {
        root /;
    }

    # TODO add media directory

    client_max_body_size 100M;

    location / {

        client_body_buffer_size 500K;
        client_max_body_size 100M;
        keepalive_timeout 43200;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 43200;
        proxy_read_timeout 43200;
        proxy_pass http://127.0.0.1:8000/;
    }
}

我还在我的 Django 项目中打开了DEBUG=True。没有运气 - 我仍然收到 Nginx 502 Bad Gateway 错误(而对于其他错误,如 404,我按预期看到了 Django 错误页面)。

当我在使用--log-level=DEBUG 运行 Gunicorn 时触发此错误时,输出如下所示:

[2017-01-22 05:17:22 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:23 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:24 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:25 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:25 +0000] [1100] [INFO] Booting worker with pid: 1100
[2017-01-22 05:17:26 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:26 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:27 +0000] [1042] [DEBUG] 4 workers
[2017-01-22 05:17:28 +0000] [1042] [DEBUG] 4 workers

处理请求的工作人员似乎默默地死去,然后默默地重生。

如果我运行 Django 开发服务器(使用 python manage.py runserver 127.0.0.1:8000)而不是 Gunicorn,则视图可以正常工作。所以这似乎是我的 Gunicorn 配置而不是我的 Python/Django 代码的问题。

我认为这并不重要,但以防万一:一切都在 Docker 容器中运行。

【问题讨论】:

  • 谷歌搜索表明 Nginx 错误表明后端出现问题。也许Job.objects.all() 是一个异常大的查询,会导致堆栈中的某些内容中断?如果您使用 jobs: [] 但将 jobs 查询提取到 Python 列表中,该视图是否有效?如果您使用jobs: dummy_array,其中dummy_array 大约与预期的jobs 结果一样长?
  • 请发布您的模板。

标签: python django nginx docker gunicorn


【解决方案1】:

问题是缺少系统资源。我在具有 512MB RAM 的 Digital Ocean 液滴上运行代码。我在向问题中提到的 Django 视图发出请求时运行了htop,我看到当 Gunicorn 工人死亡时 RAM 使用量已达到最大值。一旦我升级到具有 1GB RAM 的 droplet,这个问题就消失了。有趣的是,Django 开发服务器处理了 Gunicorn 阻塞的请求。

【讨论】:

  • 由于您使用的是-w 4,Gunicorn 比开发服务器消耗更多内存是正常的。
  • 这是有道理的,但即使只有一名工人在工作,这是真的吗? (这是一个私人开发服务器,所以我是唯一的用户。)
  • 一名工人正在工作并消耗了大部分内存,但也有其他三名工人坐着无所事事,每个人可能消耗了几十 MB。与 Django 开发服务器相比,它们可能是压死骆驼的最后一根稻草。
猜你喜欢
  • 2012-08-30
  • 2016-11-18
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 2018-08-24
  • 2015-04-25
  • 2021-01-02
  • 2013-08-12
相关资源
最近更新 更多