uWSGI + Nginx 部署 Django 笔记

前言

昨天突然之间想到,django 的请求耗时有点,有没有办法进行优化,并且提高其并发性呢,于是去网上一搜,发现好多都是基于 uWSGI + Nginx + Linux 内核的部分设置来进行优化的。所以今天我就写下其中的部署过程以及踩到的坑。

1. uWSGI

什么是WSGI?什么又是uWSGI?

通过搜索,可以知道,其实 WSGI(Web Server Gateway Interface) 是一个协议,这个协议是位于 Application 以及服务器之间,只要遵循这个协议,基于 WSGI 的应用可以跑在任何一种服务器上。而 uWSGI 这是基于 C 实现 WSGI 的服务器。注意这句话,后面遇到的坑就是跟 uWSGI 有关的。

WSGI 原理

在廖雪峰大神的网站上可以简单的了解到 WSGI 的原理以及流程是怎么样的,以下我再来简单说说: 首先一个应用要实现 WSGI 协议,主要就是应用在方法内要处理两个东西, 一个是 environ, 一个是回调函数 start_responseenviron 是一个包含了所有 HTTP 请求信息的dict对象,而 start_response 则是发送 HTTP 响应的函数。来看下大神的例子

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, web!</h1>'

这个 application 很简单, 就是直接传 response code 和 header 到 start_response 中,然后返回 response 的 body 内容。

那如果是 Django 的 application 呢,我查了下源码,他的 application 是一个 WSGIHandler 对象。整个处理流程也不长,源码如下:

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()

    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = list(response.items())
        for c in response.cookies.values():
            response_headers.append(('Set-Cookie', c.output(header='')))
        start_response(status, response_headers)
        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
            response = environ['wsgi.file_wrapper'](response.file_to_stream)
        return response

注意:内置函数 call , 在 WSGIHandler()(environ, start_response) 的时候调用

根据源码可以知道步骤如下:

  1. 根据 environ 设置脚本前缀
  2. singals 中的 request_started ( Signal 对象) 发送 environ
  3. 通过 request 获取 response
  4. 获取 response 的 status 以及 header , 调用 start_response 方法
  5. 返回 response

接着 server 要怎么处理呢,看下下面摘抄的代码。

# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application

# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print("Serving HTTP on port 8000...")
# 开始监听HTTP请求:
httpd.serve_forever()

创建 server 的时候, 在 make_server 方法内传入 server 的 ip, 端口, 处理的应用是啥就行了。

安装 uwsgi

Linux 下安装 uwsgi 比较简单,在有 pip 的情况下直接 pip install uwsgi 就行了

Windows 下比较麻烦, 因为 windows 下 python 的 os 模块 没有 uname() 方法 ,所以需要通过修改源码进行安装。再者 uwsgi 是用C语言写的,需要编译,要用 MinGW 来编译(注意了,当初我以为 git 里面的 MinGW64 能用,事实上是不能的,因为没有 GCC 编译器,只能用官网的方法来进行安装)。

先下载源码,然后找到 uwsgiconfig.py 文件中,首先 import platform 后,将 os.unam() 都改为 platform.uname()。 昨天我用 MinGW 来安装还是报错,今天上网查了下,发现原来是 MingGW 还是不支持 Windows ......

uwsgi 配置

要配合 nginx 使用的话,需要两个配置文件,一个是启动配置文件,一个是 uswgi_params 文件(用来建立 wsgi - nginx 的请求参数映射关系的,如果这个不存在的话,会出现 502 bad gateway 错误)。

启动文件的配置如下(我将它命名为uwsgi.ini)

[uwsgi]
# 设置这个值以后,可以用localhost:8888访问uwsgi
http = :9999
# socket 连接,指的是nginx反向代理的时候会用这个端口
socket = 127.0.0.1:8888
# Django 项目根目录
chdir = /home/ubuntu/web/mini-program-admin/simama_mall
# Django wsgi 文件
wsgi-file = simama_mall/wsgi.py
# 最大进程数
processes = 2
# 每个进程的最大线程数
threads = 2

# 监控台地址
status = 127.0.0.1:10000
# 是否清除环境
vacuum = true
# 日志地址
daemonize = /home/ubuntu/web/mini-program-admin/simama_mall/uwsgi.log
# pid文件 用于 uwsgi --stop uwsgi.pid (关闭服务或者重启,重启就是把 --stop 改为 --reload)
pidfile = /home/ubuntu/web/mini-program-admin/simama_mall/uwsgi.pid

uswgi_params 配置文件是这样的(文件名就是uswgi_param)

uwsgi_param QUERY_STRING        $query_string;
uwsgi_param REQUEST_METHOD      $request_method;
uwsgi_param CONTENT_TYPE        $content_type;
uwsgi_param CONTENT_LENGTH      $content_length;

uwsgi_param REQUEST_URI     	$request_uri;
uwsgi_param PATH_INFO       	$document_uri;
uwsgi_param DOCUMENT_ROOT       $document_root;
uwsgi_param SERVER_PROTOCOL     $server_protocol;
uwsgi_param UWSGI_SCHEME        $scheme;

uwsgi_param REMOTE_ADDR     	$remote_addr;
uwsgi_param REMOTE_PORT     	$remote_port;
uwsgi_param SERVER_PORT     	$server_port;
uwsgi_param SERVER_NAME     	$server_name;

启动

启动命令: uwsgi --ini uwsgi.ini

重启:uwsgi --reload uwsgi.pid

停止:uwsgi --stop uwsgi.pid

2. nginx

在做了上述的 uwsgi 设置之后,我们还需要对 nginx.conf 进行修改,修改如下

worker_processes 2; #指定开启2个worker进程
worker_rlimit_nofile 20000; # 此指令的值将覆盖ulimit的值,用于修改当前worker运行用户的最大文件打开数值

events {
    worker_connections 20000; #设置worker进程最大打开的连接数
    multi_accept on;
}

http {

    keepalive_timeout 0; # 高并发下设为0  上传文件等长连接要保持连接
    
    upstream test-django {
        # 对应 uwsgi.ini 的 socket 参数 
	    server 127.0.0.1:8888;
    }
    
    server{
        location / {
            uwsgi_pass test-django;
            uwsgi_connect_timeout 600;
            uwsgi_read_timeout 600;
            # 这里需要include uwsgi_params 文件,否则会有 502 错误
            include /home/ubuntu/web/mini-program-admin/simama_mall/uwsgi_params;
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
		}
    }
}

接着重启 nginx 就可以了

nginx.conf 位置: /etc/nginx/nginx.conf

重启命令:service nginx restart

3. Linux TCP 优化

有两种方法对 Linux 内核进行修改:

1. 逐个配置文件修改

    # 修改允许等待中的监听
    echo 50000 >/proc/sys/net/core/somaxconn  
    # 修改tcp连接快速回收
    echo 1 >/proc/sys/net/ipv4/tcp_tw_recycle
    # 修改tcp连接重用 
    echo 1 >/proc/sys/net/ipv4/tcp_tw_reuse 
    # 不抵御洪水攻击
    echo 0 >/proc/sys/net/ipv4/tcp_syncookies
    
2. 修改 /etc/sysctl.conf,然后执行 sysctl -p,具体增加内容如下
    net.core.somaxconn = 20000
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_syncookies = 0

4. ab 测试

进行了上面的修改之后,我用了apache的ab.exe 进行压力测试,结果........

Benchmarking test.ranking.pub (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.10.3
Server Hostname:        test.ranking.pub
Server Port:            80

Document Path:          /goods/consume
Document Length:        170 bytes

Concurrency Level:      100
Time taken for tests:   8.681 seconds
Complete requests:      1000
Failed requests:        0
Non-2xx responses:      1000
Total transferred:      387000 bytes
HTML transferred:       170000 bytes
Requests per second:    115.20 [#/sec] (mean)
Time per request:       868.081 [ms] (mean)
Time per request:       8.681 [ms] (mean, across all concurrent requests)
Transfer rate:          43.54 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    8   7.8     15      31
Processing:     0  817 148.7    860     882
Waiting:        0  449 247.0    453     875
Total:         16  825 148.6    860     891

Percentage of the requests served within a certain time (ms)
  50%    860
  66%    875
  75%    875
  80%    875
  90%    876
  95%    881
  98%    881
  99%    891
 100%    891 (longest request)

测试结果并不是太好,感觉应该因为服务器性能太差(腾讯云的学生优惠服务器)

 

PS : 这是我的第一篇博客,上面的内容有部分参考网上的博客,如果写的不好,或者有什么疑问或者问题,大家可以在下方指出,谢谢大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值