了解到uwsgi也是支持websocket的,所以便使用这种熟悉的支持wsgi协议的web服务器来部署。
访问网页测试时,出现了报错
Internal Server Error
查看了uwsgi.log后,发现提示:
— no python application found, check your startup logs for errors —
报错有两个可能的原因:
成功启动nginx与uwsgi后,再次访问网页进行测试, 出现报错:
WebSocket connection to 'xxx‘ failed:
然后websocket连接就关闭了。
查询代码后,发现网络请求是到@accept_websocket时停止的,猜测是因为websocket连接无法成功连接。请教了身边的同事后,了解到可能是因为nginx配置不支持websocket连接。
在网上一番搜索后,在项目nginx下的配置文件中加入了支持websocket的连接。
在location中加入了websocket配置。
location / {
# uwsgi启动
uwsgi_send_timeout 600; # 指定向uWSGI传送请求的超时时间,完成握手后向uWSGI传送请求的超时时间。
uwsgi_connect_timeout 600;
uwsgi_read_timeout 600;
include /usr/local/nginx/conf/uwsgi_params;
uwsgi_pass 127.0.0.1:9997;
# websocket的匹配
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
将nginx重启应用新的配置文件。
nginx -s reload -c /路径/nginx.conf
成功重启nginx与,再次访问网页进行测试, 出现报错:
WebSocket connection to 'xxx‘ failed:
一样的报错,这让我不能理解了,遇到不能理解的事情时,只能期待google能够为我解释。于是在网上继续搜索,发现了dwebsocket的github,通过readme文件中的操作,尝试验证了一番。
Change websocket backends
Currently supports two kinds of backends, they are default and uwsgi.
Django develop server, eventlent, gevent, gunicore are supported by default.
If you want to use the uwsgi backend, add WEBSOCKET_FACTORY_CLASS in the settings.py file:
WEBSOCKET_FACTORY_CLASS = 'dwebsocket.backends.uwsgi.factory.uWsgiWebSocketFactory'
Run uwsgi:
uwsgi --http :8080 --http-websockets --processes 1 --wsgi-file wsgi.py --async 30 --ugreen --http-timeout 300
这段话的意思是,dwebsocket目前支持两种类型的后端,default与uwsgi。ps: default我认为就是在开发时使用的runserver命令。默认支持django开发服务器,eventlent,gevent,gunicore。eventlent与gevent都是python中支持协程第三方库。ps:不知道是不是作者敲错字了,我理解的gunicore应该是gunicorn,一个wsgi的容器,支持wsgi的应用服务器。
如果想使用uwsgi作为后端,应该在项目的settings.py中配置
WEBSOCKET_FACTORY_CLASS = 'dwebsocket.backends.uwsgi.factory.uWsgiWebSocketFactory'
启动uwsgi时使用命令
uwsgi --http :8080 --http-websockets --processes 1 --wsgi-file wsgi.py --async 30 --ugreen --http-timeout 300
github中的这一串命令应该是打错了,官网中wsgi.py与–async中间没有空格,导致运行时会报错。
用此命令启动uwsgi,由于此时是用uwsgi启动的,没有经过nginx,直接访问8080端口。打开网页进行测试,css样式全部消失了,一按F12,发现原来都找不到静态文件。确定路径都没有问题后,google一下。原来是命令中没有配置静态文件的路径,于是将命令更新为:
uwsgi --http :8080 --http-websockets --processes 1 --wsgi-file wsgi.py --async 30 --ugreen --http-timeout 300 --static-map /static=/路径/static
成功运行项目。ps:运行此命令时,建议在项目根路径下,与manage.py同级。将命令中wsgi.py替换成“项目名/wsgi.py",否则可能会报错no application,或者no module named ”项目名“的错误。
此处参考https://note.qidong.name/2017/07/uwsgi-serve-django-static/。
而且一行命令太长了,所以将其写成一个配置文件xxx_uwsgi.ini在后台,启动或配置更方便。
# xxx_uwsgi.ini
[uwsgi]
http=:8080
http-websockets=True
processes=1
wsgi-file=xxx/wsgi.py
async=30
ugreen=True
http_timeout=300
static-map=/static=/路径/static
; 设置日志目录
daemonize=/路径/log/uwsgi.log
; 停止时自动删除进程号文件
vacuum = true
pidfile=/路径/test_train.pid
虽然使用uwsgi启动项目成功了,但是通过测试项目发现,当有一个用户进行websocket长连接后,另一个用户便无法连接了,原因是uwsgi配置文件中的processes进程只配置了一个,websocket长连接占据了这个进程,导致了阻塞。
可是当我将processes进程数量设为2后,虽然可以两个用户连接了,但是并不能三个用户同时连接,这显然是不合理的。并且用户与用户之间的进程不通信,所以协同的功能就没有了。
经过一番搜寻后,没有找到好的解决方案,所以就弃用了uwsgi作为Web服务器的方案。
舍弃了uwsgi作为web服务器方案后,尝试github中给出的第二种Web服务器gunicorn。
首先需要在Django项目下settings.py中的installed_apps加入gunicorn:
INSTALLED_APPS=[
...
...
'gunicorn', # 部署用
]
在项目目录下,gunicorn启动语法:
gunicorn --worker-class=gevent 项目名.wsgi:application -b 127.0.0.1:8000&
如果出现下面的报错:
ModuleNotFoundError: No module named 'uwsgi'
回到settings.py文件中将WEBSOCKET_FACTORY_CLASS配置项注释掉,重新运行命令即可。
使用gunicorn启动时发现一个问题,当第二个客户端连接进入的时候,会找不到静态文件,暂时不知道为什么。
使用gunicorn启动项目时,第二个客户端连接上去找不到静态文件,猜测可能是因为静态文件占用问题。所以使用nginx作为静态文件服务器,并转发网络请求。
nginx文件配置:
location /static {
alias /home/xxx/static;
}
location / {
#gunicorn配置
proxy_pass http://127.0.0.1:9997;
proxy_http_version 1.1;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
为了方便gunicorn文件的配置,将其写到gunicorn.py文件中。
bind = '127.0.0.1:9997' # 绑定ip与端口号
backlog = 512 # 监听队列
chdir = '/home/xxx/项目名'
# 使用gevent模式,还可以使用sync 模式,默认的是sync模式
worker_class = 'gevent'
loglevel = 'info' # 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置
errorlog = '/home/xxx/logs/gunicorn.error.log' #错误日志
accesslog = '/home/xxx/logs/gunicorn.access.log' #访问日志
daemon = True # 后台运行
启动nginx:
nginx -c "/绝对路径/xxx_nginx.conf"
以nohup将gunicorn在后台保持运行:
nohup gunicorn -c gunicorn.py 项目名.wsgi:application
到这里,成功的将项目部署好了。