zoukankan      html  css  js  c++  java
  • django+channels+dephne实现websockrt部署

    当你的django项目中使用channels增加了websocket功能的时候,在使用runserver命令启动时,既可以访问http请求,又可以访问websocket请求。但是当你使用uWSGI+nginx的来启动项目的时候,你会发现http请求可用,但是websocket请求永远是404的错误。这是为什么呢?

    因为在我们的标准生产环境部署中,使用的事WSGI协议来启动的我们的项目,也就是使用的wsgi.py这个文件来对接的uWSGI服务器。但是我们channels使用的ASGI协议,在我们使用uWSGI来启动项目的时候,关于ASGI的一些配置他就找不到了。这就导致了你所有的websocket请求都是404。在查阅了大量的资料和阅读了官方文档以后终于解决了这个问题。

    这个问题的解决有两种方案:

    • 启用uWSGI来处理所有的http请求,另外开启一个daphne服务来处理websocket请求。这样的好处是按照请求类型分流,两种请求方式互不干扰。

    • 另外一种则是启用daphne服务来处理http和websocket这两种请求。在daphne服务内部他会根据请求类型的不同分开处理。让你既可以访问websocket又可以访问http。

    安装Daphne

    pip install daphne

    在setting.py同级的目录下新建一个asgi.py文件

    """
    ASGI entrypoint. Configures Django and then runs the application
    defined in the ASGI_APPLICATION setting.
    """
    
    import os
    import django
    from channels.routing import get_default_application
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
    django.setup()
    application = get_default_application()

    使用Daphne来启动项目

    daphne -b 0.0.0.0 -p 8000 myproject.asgi:application

    这种方式只是在后台启动了你的项目,我们为了保证项目的稳定性,保证项目在意外死亡以后可以迅速的重启,我们来使用supervisor来管理我们的daphne服务。

    什么是supervisor

    1. Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。

    1. 作用:它可以很方便的监听、启动、停止、重启一个或多个进程。

    1. 用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起

    1. 很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

    1. 说白了,它真正有用的功能是俩个将非daemon(守护进程)程序变成deamon方式运行对程序进行监控,当程序退出时,可以自动拉起程序。

    1. 但是它无法控制本身就是daemon的服务。

    安装supervisor

    yum install epel-release
    
    yum install supervisor

    不要使用pip下载supervisor,因为系统有python2.7和python3.6两个版本,有时候会因为版本问题倒是supervisor启动错误。而且pip的supervisor的安装和使用方式也更为繁琐一些。

    在/etc/supervisord.d/文件夹下面配置被管理的服务的配置,然后启动supervisor即可管理该服务。

    下面使用supervisor来管理我们dephne服务

    [program:asgi]
    directory=/code/shiyanloupro/
    command=daphne -b 0.0.0.0 -p 8000 --proxy-headers shiyanloupro.asgi:application
    autostart=true
    autorestart=true
    stdout_logfile=/tmp/websocket.log  #日志
    redirect_stderr=true
    /etc/supervisord.d/test.ini

    supervisor的管理命令

    [root@linux-node1 tmp]# supervisord -c /etc/supervisord.conf  # 启动supervisor
    [root@linux-node1 tmp]# systemctl enable supervisord    # 开机自启动
    [root@linux-node1 tmp]# systemctl start supervisord     # 启动supervisord服务
    [root@linux-node1 tmp]# supervisorctl reread                    # 重新读取多有的配置文件
    [root@linux-node1 tmp]# supervisorctl update            # 配置文件修改后使用该命令加载新的配置,常和reread连用
    [root@linux-node1 tmp]# supervisorctl reload            # 重新启动配置中的所有程序
    
    [root@linux-node1 tmp]# supervisorctl status            # 查看supervisor管理的所有进程状态
    [root@linux-node1 supervisord.d]# supervisorctl restart test            # 启动test程序
    [root@linux-node1 supervisord.d]# supervisorctl stop all                # 停止所有程序
    [root@linux-node1 supervisord.d]# supervisorctl stop es       # 停止名称es程序(如果停止所有换成all)
    [root@linux-node1 tmp]# supervisorctl start es      # 启动项目名称es程序

    接下来就是配置nginx将请求转发到daphne服务器

    upstream channels-backend {
        server localhost:8000;
    }
    ...
    server {
        ...
        location / {
            try_files $uri @proxy_to_app;
        }
        ...
        location @proxy_to_app {
            proxy_pass http://channels-backend;
    
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    
            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;
            proxy_set_header X-Forwarded-Host $server_name;
        }
        ...
    }
    /etc/nginx/nginx.d/daphne.conf

    最后来开启你的nginx服务和dephne服务即可。

    systemctl restart nginx   #重启nginx
    supervisorctl reread            #重新读取supervisor的配置
    supervisorctl update            #更新supervisor的配置
    supervisorctl start asgi    #启动asgi服务,也就是我们的daphne服务
  • 相关阅读:
    解决:std::ostream operator<< should have been declared inside 'xxx'
    c++ friend 遇到 namespace 无法访问 private 成员的问题
    Compiler Error C2872: ambiguous symbol
    【持续更新】总结:C++开发时积累的一些零碎的东西
    陷阱:C++模块之间的”直接依赖“和”间接依赖“与Makefile的撰写
    ZThread::ThreadLocal:ERROR C4716 must return a value的解决
    java值传递
    iframe与父页面传值
    iframe父子兄弟之间调用传值(contentWindow && parent)
    MySQL返回影响行数的测试示例
  • 原文地址:https://www.cnblogs.com/ppzhang/p/12917606.html
Copyright © 2011-2022 走看看