跟老刘学python

新猿教育老刘带你学习python,学完即可就业。

0基础python教程 Python项目高并发异步部署实战+压测

接着上一章,往下学习,本章主要讲解Python项目高并发异步部署实战+压测,学习的小伙伴千万不能错过本课,本课是实践课非常的重要哦~~~

## 1 前言

由于Python有把大锁GIL,会将多个线程在同一时刻,只能有一个线程执行,变成'串行',所以一个多线程python进程,并不能充分使用多核CPU资源,所以对于Python进程,可采用多进程部署方式比较有利于充分利用多核的CPU资源,而uWSGI服务器就是这么一个东西,可以以多进程方式执行WSGI app,其工作模式为 1 master进程 + N worker进程+m个线程(N*m线程),主进程负责接收客户端请求,然后将请求转发给worker进程,因此最终是worker进程负责处理客户端请求,这样很方便的将WSGI app以多进程方式进行部署**此方式是企业常用部署方式**

**但是存在一个问题**

客户端向uwsgi的一个master发起一个HTTP请求,master分发给不同的worker进程,worker进程拉起线程处理请求,进入web框架,直到该请求处理完,这个线程才能处理其他请求,所以wsgi app是同步的。假如一个请求处理花费时间比较久,客户端请求数量又比较多的情况下,所有的线程都会被占满,所以就处理不了更多的请求(最大连接数取决于进程N*线程M)

**我们的处理方案**

1)增大N,即worker的数量:在增加进程的数量的时候,进程是要消耗内存的,并且如果进程数量太多的情况下(并且进程均处于活跃状态),进程间的切换会消耗系统资源的,所以N并不是越大越好。一般情况下,可能将进程数目设置为CPU数量的2倍

2)增大m,即worker的线程数量:线程创建也是有限度的,由于线程栈是要消耗内存的,线程数量太多也不行

于是我们想,一条线程能不能同时处理多个请求呢?可以使用IO多路复用的模型

**于是,gevent登场了**

gevent是用户态的'线程',也就是协程,单线程下实现并发

gevent的好处就是无需等待I/O,当发生I/O调用是,gevent会主动切换到另一gevent进行运行,这样可以充分利用CPU资源

同时gevent通过monkey patch(猴子补丁)替换掉了标准库中阻塞的模块

## 2 以flask项目为例,使用uwsgi+gevent部署高并发实战

### 2.1 新建flask项目 (s1.py)

```python

from flask import Flask

import time

app = Flask(__name__)

@app.route('/')

def hello_world():

    time.sleep(1) # 引入io操作

    return 'Hello World!'

if __name__ == '__main__':

    app.run()

```

## 2.2 新建uwsgi.py

```python

[uwsgi]

http = 0.0.0.0:5000

chdir = /root/20210318/

wsgi-file = /root/20210318/s1.py

processes = 2

threads = 8

buffer-size = 32768

master = true

pidfile = uwsgi.pid

daemonize = uwsgi.log

callable = app

---------------------------

[uwsgi]

http = 0.0.0.0:5000 # 监听地址和端口

chdir = /root/test/ # 项目路径

wsgi-file = /root/test/s1.py # py文件路径

processes = 1 # 进程数

threads = 1   # 线程数

buffer-size = 32768 # 缓存大小

master = true       #允许主进程存在

pidfile = uwsgi.pid # pid位置

daemonize = uwsgi.log#日志文件

callable = app   #flask中flask对象的名字,flask部署需要配置它

-----------uwsgi其他参数------------------

socket : 地址和端口号,例如:socket = 127.0.0.1:50000

processes : 开启的进程数量

workers : 开启的进程数量,等同于processes(官网的说法是spawn the specified number of  workers / processes)

chdir : 指定运行目录,项目根路径(chdir to specified directory before apps loading)

wsgi-file : 载入wsgi-file,wsgi文件,flask就是app.py(load .wsgi file)

stats : 在指定的地址上,开启状态服务(enable the stats server on the specified address)

threads : 运行线程。(run each worker in prethreaded mode with the specified number of threads)

master : 允许主进程存在(enable master process)

daemonize : 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器(daemonize uWSGI)。实际上最常用的,还是把运行记录输出到一个本地文件上。

log-maxsize :以固定的文件大小(单位KB),切割日志文件。 例如:log-maxsize = 50000000  就是50M一个日志文件。

pidfile : 指定pid文件的位置,记录主进程的pid号。

vacuum : 当服务器退出的时候自动清理环境,删除unix socket文件和pid文件(try to remove all of the generated file/sockets)

disable-logging : 不记录请求信息的日志。只记录错误以及uWSGI内部消息到日志中。如果不开启这项,那么你的日志中会大量出现这种记录:

log-maxsize : 日志大小,当大于这个大小会进行切分 (Byte)

log-truncate : 当启动时切分日志

buffer-size : 比如前端(客户端)向后端(服务器)发了一个请求,请求的大小是5M,那么buffer-size的大小就得大于1024*5,不然就报错了

callable :app  #变量app 与 App.py文件中的app = Flask(__name__)对应

```

## 2.3 在centos7.5机器上测试

>第一步:安装python3.6环境(略)

>

>第二步:安装uwsgi (pip3 install uwsgi)

>

>    -uwsgi在1.4版本以上,就支持gevent(官方介绍:https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Gevent.html)

>

>第三步:安装flask    (pip3 install flask)

>

>第四步:安装gevent   (pip3 install gevent)

## 2.4 首先不使用gevent启动uwsgi

>uwsgi uwsgi.ini

## 2.5 使用gevent启动uwsgi

>

>uwsgi --gevent 100 --gevent-monkey-patch uwsgi.ini

>

## 2.6 压测两个接口

>ab -n 10 -c 5 https://101.133.225.166:5000/

>

>不使用gevent跑,可以看到 requests per second (每秒请求数为0.99)

>ab -n 10 -c 5 https://101.133.225.166:5000/

>

>使用gevent跑,可以看到 requests per second (每秒请求数为3.28)


评论