Django Channels Nginx 生产环境

22

我有一个 Django 项目,最近添加了 Channels 来使用 WebSockets。这似乎都能正常工作,但我的问题是如何将其准备好生产环境。

我的设置如下:

Nginx web server
Gunicorn for django
SSL enabled

由于我已经添加了频道,所以过去一天我都在尝试让它工作。

在所有的教程中,他们都说你需要在某个端口上运行Daphne然后展示如何为其设置nginx。

但是,如果要使用gunicorn来服务django呢?

现在我已经让gunicorn在8001端口上运行了这个django应用程序。

如果我在另一个端口(比如8002)上运行daphne,它应该如何知道它是这个django项目的一部分?而且,怎么运行工作进程?

是不是Gunicorn、Daphne和工作进程都需要同时运行?









我不确定你是否真的需要两者?我没有使用过Daphne,所以我可能是错的。请检查一下这个帖子是否有帮助 https://dev59.com/1lgQ5IYBdhLWcg3wqFoF - Tarun Lalwani
3个回答

26
这个问题实际上在最新的Django Channels文档中有所提及:
引入公共路径前缀,如/ws/,以区分WebSocket连接和普通HTTP连接是很好的做法,因为它将使得在某些配置下将Channels部署到生产环境变得更加容易。特别是对于大型网站,可以配置像nginx这样的生产级别HTTP服务器,根据路径将请求路由到(1)生产级别的WSGI服务器,如Gunicorn+Django用于普通HTTP请求或(2)生产级别的ASGI服务器,如Daphne+Channels用于WebSocket请求。
请注意,对于较小的网站,您可以使用更简单的部署策略,其中Daphne服务于所有请求-HTTP和WebSocket-而不是拥有单独的WSGI服务器。在这种部署配置中,不需要像/ws/这样的公共路径前缀。
实际上,您的NGINX配置看起来应该像这样(仅包含相关部分的缩写):
upstream daphne_server {
  server unix:/var/www/html/env/run/daphne.sock fail_timeout=0;
}

upstream gunicorn_server {
  server unix:/var/www/html/env/run/gunicorn.sock fail_timeout=0;
}

server { 
  listen   80; 
  server_name _;

  location /ws/ {
    proxy_pass http://daphne_server;
  }

  location / {
    proxy_pass http://gunicorn_server;
  }
}

(假设您将Gunicorn和Daphne服务器绑定到Unix套接字文件。)


如果我理解正确,gunicorn替换了worker?因此不需要运行python manage.py runworker吗? - user3672754
经过一些测试,不需要使用“runworker”。 - user3672754
1
只有在使用Django Channels 2.x运行工作程序或后台进程时,才需要执行“python manage.py runworker”命令(https://channels.readthedocs.io/en/latest/topics/worker.html)。通常情况下,您会使用类似celery的工具来完成这个任务(文档链接中提到了原因)。 - Kal
在Channels 3.0.3中是一样的吗? - Abhijith Konnayil
我刚刚查看了v3版本的发布说明,看起来它不应该对部署产生任何影响。文档中包含的官方部署指南(https://channels.readthedocs.io/en/stable/deploying.html#configuring-the-asgi-application)也建议以上解决方案仍然适用。如果您发现有不同的情况,请在此处添加您的答案或让我知道,以便我进行调查并更新我的答案。 - Kal

7
我已经创建了一个 示例,介绍如何混合使用Django Channels和Django Rest Framework。我设置了nginx路由,使得:

  • WebSockets连接将转到Daphne服务器
  • HTTP连接(REST API)将转到Gunicorn服务器

这是我的nginx配置文件:

upstream app {
    server wsgiserver:8000;
}

upstream ws_server {
    server asgiserver:9000;
}


server {
    listen 8000 default_server;
    listen [::]:8000;

    client_max_body_size 20M;

    location / {
        try_files $uri @proxy_to_app;
    }

    location /tasks {
        try_files $uri @proxy_to_ws;
    }

    location @proxy_to_ws {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect off;

        proxy_pass   http://ws_server;
    }

    location @proxy_to_app {
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Url-Scheme $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        proxy_pass   http://app;
    }

}

2

我最近回答了一个类似的问题,你可以看一下那个问题来了解django channels是如何工作的。

基本上,你不再需要gunicorn。你有daphne,它是接受HTTP/Websockets的接口服务器,而你的worker运行django视图。然后,你当然还有连接所有东西的channel后端。

为了使其工作,你需要在settings.py中配置CHANNEL_LAYERS,并运行接口服务器:

$ daphne my_project.asgi:channel_layer

以及你的worker:

$ python manage.py runworker

注意!如果你选择redis作为channel后端,请注意你所提供的文件大小。如果你有大型静态文件,请确保NGINX服务它们,否则客户端将遇到由于redis内存不足而可能发生的隐晦错误。


我不建议使用Daphne作为处理HTTP的WSGI,因为它需要比Gunicorn工作进程接收HTTP流量更多的资源。 - Dean Christian Armada
不建议在生产环境中使用Daphne。 - user3672754
3
谁不建议在生产中使用Daphne? 不是官方的Django-channels文档。 - Markus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接