django-channels的部署(supervisor+daphne+nginx)
项目中需要一个聊天室的功能,所以需要websocket通信,选择了使用channels
模块,主要记录下channels
部署的配置和一些坑.
原项目是通过nginx+uwsgi部署的,这里我没做任何改动,只是通过Nginx将特定请求路径代理到daphne上.部署前对django
配置的一些修改可以直接参考官方文档,这个比较简单,也没有什么问题.
supervisor + daphne
第一种:
这是我最初在网上查到配置,很多文章基本是类似的:
[program:asgi]
directory=/your/path/project-name # 项目主路径
command=daphne -b localhost -p 8001 --proxy-headers project-name.asgi:application # 启动命令
autostart=true
autorestart=true
stdout_logfile=/tmp/asgi.log
redirect_stderr=true
需要注意一点,如果项目运行在虚拟环境,supervisor安装在主环境中,那么daphne
需要用绝对路径.
这种配置是可用的,但有个问题是只能单进程运行,如果打开多个进程(添加numprocs=n
)会报端口占用的错误.
第二种
然后就是官方的配置,文档中提供的配置是多进程的,但有一个小问题,先贴出我的配置:
[fcgi-program:asgi]
socket=tcp://localhost:8001
directory=/my/app/path
# 区别在这里
command=daphne --fd 0 --access-log - --proxy-headers mysite.asgi:application
###########
numprocs=4
process_name=asgi%(process_num)d
autostart=true
autorestart=true
stdout_logfile=/your/log/asgi.log
redirect_stderr=true
注意:fcgi-program是做了一层代理的,现在一个网络请求的传递就是:nginx -> supervisor -> daphne -> backend-app.
所以这里daphne绑定的unix-socket或者文件描述符都是用来与supervisor通信的,这就与上面第一种配置不同了
我去掉了-u xxx/xxx.sock
的配置项,因为这一项是没有必要的.在命令行中看一下daphne
的帮助,里面有这样两条:
--fd FILE_DESCRIPTOR
选项会绑定到一个文件描述符,并替换掉对host/port和unix-socket的绑定.
注意: 根据supervisor:fcgi-program的文档,fcgi-program中部署的程序只能通过文件描述符0与supervisor进行通信.所以这里如果只用unix-socket其实是无效的.
nginx
nginx的配置基本参考channels的文档:
upstream channels-backend {
server localhost:8001;
}
...
server {
...
location /ws/ {
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;
}
...
}
(我其实没有搞懂文档里提到的try_files的用法-_-!)
我遇到的一个小问题,起初我在supervisor配置里用了
127.0.0.1
,然后在nginx里用了localhost
,发现居然连不通,这才第一次意识到他两个是有区别的.
因为localhost
的传输不走网卡,不受网卡或防火墙的限制,所以建议本地程序间通信用localhost
.
原文地址:https://www.cnblogs.com/thunderLL/p/11731756.html
- Sublime text 3 中Package Control 的安装与使用方法
- 用functools.lru_cache实现Python的Memoization
- 腾讯互联网与社会研究院秘书长司晓:将联合开展研究合作
- 幻灯片jQuery插件Orbit 介绍(附添加到WordPress教程)
- Gravatar开发者手册
- Gravatar开发者手册
- 使用Google CDN服务提供的jQuery库
- 比特币的分叉币都认为能够取代比特币,事实真的是这样吗?
- Google官方网页载入速度检测工具PageSpeed Insights 使用教程
- ASP.NET 路由
- Kafka定时清除过期数据
- 腾讯高级副总裁郭凯天:打造腾讯智库分析互联网产业前沿问题
- Google Chrome 浏览器 开发者工具 使用教程
- 反向代理(Reverse Proxy)及 IIS 7 应用请求路由模块
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 通过PHP设置BugFree获取邮箱通知
- Django封装交互接口代码
- 使用K.function()调试keras操作
- tensorflow图像裁剪进行数据增强操作
- ThinkPHP3.2.3框架Memcache缓存使用方法实例总结
- Python+PyQt5+MySQL实现天气管理系统
- 浅谈Python协程
- Python logging模块异步线程写日志实现过程解析
- php-fpm重启导致的程序执行中断问题详解
- Python Socket TCP双端聊天功能实现过程详解
- django 将自带的数据库sqlite3改成mysql实例
- 利用python对mysql表做全局模糊搜索并分页实例
- PHP chop()函数讲解
- Linux下安装Memcached服务器和客户端与PHP使用示例
- PHP xpath()函数讲解