Django uwsgi asgi(websocket) nginx部署项目

     阅读:38

Uwsgi

uWSGI 配置文件中 Magic variables的含义 前缀为百分号:


%v	   vassals 目录 (pwd)
%V	   uWSGI 版本
%H	   主机名
%o	   在命令行中指定的原始配置文件名
%O	   与 %o 相同,但指的是第一个非模板配置文件(版本 1.9.18%p	    配置文件的绝对路径
%P	   与 %p 相同,但参考第一个非模板配置文件(版本 1.9.18%s	   配置文件的文件名
%S	   与 %s 相同,但指的是第一个非模板配置文件(版本 1.9.18%d	   包含配置文件的目录的绝对路径
%D	  与 %d 相同,但指的是第一个非模板配置文件(版本 1.9.18%e	   配置文件的扩展名
%E	   与 %e 相同,但指的是第一个非模板配置文件(版本 1.9.18%n	   没有扩展名的文件名
%N	   与 %n 相同,但参考第一个非模板配置文件(版本 1.9.18%C	   包含配置文件的目录的名称(版本 1.3+%C	  与 %c 相同,但指的是第一个非模板配置文件(版本 1.9.18%t	  unix 时间(以秒为单位,在实例启动时收集)(版本 1.9.20-dev+%T	  unix 时间(以微秒为单位,在实例启动时收集)(版本 1.9.20-dev+%x	  当前部分标识符,例如。config.ini:section(版本 1.9-dev+%X	  与 %x 相同,但参考第一个非模板配置文件(版本 1.9.18%i	  文件的 inode 编号(版本 2.0.1%I    	与 %i 相同,但指的是第一个非模板配置文件
%0..%9	 包含配置文件的目录完整路径的特定组件(版本 1.3+%[	   ANSI 转义符“\033”(用于打印颜色)
%k	   检测到的 CPU 内核(版本 1.9.20-dev+%u	  运行进程的用户的 uid(2.0 版)
%U	   运行进程的用户的用户名(如果可用,否则回退到 uid)(版本 2.0%G	   运行该进程的用户的 gid(版本 2.0%G	   运行进程的用户的组名(如果可用,否则回退到 gid)(版本 2.0%j	   完整配置路径的 djb33x 哈希的十六进制表示
%J	  与 %j 相同,但指的是第一个非模板配置文件

先放上配置页面 uwsgi.ini文件:

[uwsgi]

#项目目录
chdir = %d../vs12_service_api

#指定IP端口,如果
;http = :8007
socket = 0.0.0.0:8008
#指定项目的application
module = vs12_service_api.wsgi:application
#进程
#启动个worker进程数量
processes = 3 
#每个worker进程中创建线程数量
threads = 3
#设置用于uwsgi包解析的内部缓存区大小单位字节。默认是4k。
buffer-size = 65535
#set cpu affinity 这个地方不太懂 以前老项目这么设置的我也拿过来用了
cpu-affinity = 1
run_dir = %(chdir)/../run
#指定pid文件
pidfile = %(run_dir)/uwsgi.pid
#指定log文件
logto = %(run_dir)/uwsgi.log
#设置最大log文件大小
log-maxsize = 100000000

# 在每个worker而不是master中加载应用。默认为false,表示先加载应用,再fork出worker,这样做可以让work尽量共用内存,只有当写时才copy
# 由于先加载再fork,但有些东西是不支持fork的,比如socket连接,所以lazy-apps=false时,不要在加载应用时自动创建数据库连接等
lazy-apps = true

uwsgi.ini 中 http 与socket 区别:

先说最简单的 http 这个是作为一个独立的服务器启动 ,然后由NGINX
作为一个比如18008端口的中介用来转发,如上面配置,浏览器或着postman, 还是能直接访问这个8007端口的 socket
是在内存中遵循socket协议和NGINX内存交换,不可以直接用浏览器或者postman直接访问

http与socket在nginx中的设置也是不一样的,文章中的nginx设置只是配置的socket的,如果是http则需要另外配置

文件目录位置

uwsgi.ini 可以放到项目中的 manage.py 文件的同级别目录下,也可以像我一样放在项目的外面,项目结构如下图,图可见 我的uwsgi.ini 放在的项目同级别文件deploy中了,所以再配置中 指定项目目录时要 通过 ”%d…/ “ 找到对应的项目
在这里插入图片描述

启动uwsig

uwsgi --ini deploy/uwsgi.ini #启动命令


[uWSGI] getting INI configuration from deploy/uwsgi.ini

可以通过 ini文件中配置的log文件 查看运行状态:

 sudo tail -n 10 -f run/uwsgi.log 
 
 
[pid: 31725|app: 0|req: 1/1] 192.168.99.134 () {46 vars in 862 bytes} [Fri Sep 10 16:23:27 2021] GET /v1/system/equipment/group => generated 7868 bytes in 314 msecs (HTTP/1.1 200) 5 headers in 177 bytes (1 switches on core 0)
/home/zhao/.virtualenvwrapper/vs12Env/lib/python3.7/site-packages/pymysql/cursors.py:170: Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.")
  result = self._query(query)
/home/zhao/.virtualenvwrapper/vs12Env/lib/python3.7/site-packages/pymysql/cursors.py:170: Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.")
  result = self._query(query)
station {'uuid': '3525f36db2c14df2a68efef29eaa2647', 'station_id': 1, 'station_name': '本地测试卫通站', 'station_code': '007', 'manager': None, 'station_type': 1, 'frequency_range': 14, 'longitude': 117.0645, 'latitude': 36.95, 'antenna_power': 40, 'antenna_aperture': 2, 'station_status': 1, 'satellite_id': 101541, 'station_ip': '192.168.99.15', 'station_port': 8007, 'inet_mask': '255.255.255.0 ', 'inet_gateway': '8010'}
[pid: 31724|app: 0|req: 1/2] 192.168.99.134 () {46 vars in 838 bytes} [Fri Sep 10 16:23:29 2021] GET /v1/station/station/info => generated 489 bytes in 223 msecs (HTTP/1.1 200) 5 headers in 150 bytes (1 switches on core 0)
[pid: 31723|app: 0|req: 1/3] 192.168.99.134 () {46 vars in 840 bytes} [Fri Sep 10 16:23:29 2021] GET /v1/system/equipment/topo => generated 518483 bytes in 262 msecs (HTTP/1.1 200) 5 headers in 179 bytes (1 switches on core 0)
[pid: 31724|app: 0|req: 2/4] 192.168.99.134 () {42 vars in 810 bytes} [Fri Sep 10 16:23:30 2021] GET /v1/system/equipment/topo?id=6 => generated 123720 bytes in 35 msecs (HTTP/1.1 200) 5 headers in 179 bytes (1 switches on core 1)

启动 websokcet的ASGI

因为本次websocket是用的django channles库,默认用的是asgi ,所以使用官方推荐的asgi服务器daphne来启动

需要用的库,django是2.2.2 如果是其他版本可能库的版本有所区别:

pip install channels==2.4.0
pip install channels-redis==2.3.2
pip install asgiref==3.2.1
pip install daphne==2.5.0

启动配置

在settings.py同级目录中添加asgi.py文件内容如下:

import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "vs12_service_api.settings")
django.setup()

from channels.auth import AuthMiddlewareStack
from channels.routing import get_default_application

from channels.auth import AuthMiddlewareStack
from channels.sessions import SessionMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import vs12_system.routing

application = ProtocolTypeRouter({
    # "http": get_default_application(),
    'websocket': AuthMiddlewareStack(
        URLRouter(
            vs12_system.routing.websocket_urlpatterns
        )
    ),

})

settings.py文件中添加配置:

INSTALLED_APPS = [
    'channels',
  	...
]
# 这里对应刚刚创建的asgi文件中的application
ASGI_APPLICATION = 'vs12_service_api.asgi.application'

在mange.py 同级目录下运行:

#跟settings文件中的ASGI_APPLICATION 相对应启动端口为 8009
#启动
daphne vs12_service_api.asgi:application -b 0.0.0.0 -p 8009 #启动命令


  [WARNING] DJANGO_SETTINGS_MODULE=vs12_service_api.settings
  Will use settings/local.py


2021-09-10 16:12:54,313 INFO     Starting server at tcp:port=8009:interface=0.0.0.0
2021-09-10 16:12:54,314 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2021-09-10 16:12:54,314 INFO     Configuring endpoint tcp:port=8009:interface=0.0.0.0
2021-09-10 16:12:54,316 INFO     Listening on TCP address 0.0.0.0:8009

具体 websocket 开发可以参考:
Django使用Channels实现WebSocket消息通知功能

踩坑

如果出现 ***AttributeError: module ‘asyncio.coroutines’ has no attribute ‘_is_coroutine’***这个错误有可能是 asgiref 的版本不对 ,安装 3.2.1版本

 pip install asgiref==3.2.1  

nginx 配置

server{
	#监听8007端口
    listen 18007;
	
	#因为webocket的 url开始是equipment所以监听 以 /equipment开头的url
     location /equipment {
        proxy_pass http://127.0.0.1:8007;
        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;
    }

    location /v1 {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #端口要和uwsgi里配置的一样
        uwsgi_pass uwsgi://127.0.0.1:8008;
        include uwsgi_params;
    }


    location / {
        root /srv/vs12prj/vs12prj/src/dist;
        try_files $uri $uri/ /index.html;
    }

}