Flask搭建服务(五):gunicorn使得服务性能降低问题及解决

1.背景

使用ab进行压测,发现使用gunicorn后,服务性能反而下降了,这是ab结果:

压测命令:$ ab -c 10 -n 1000 -p post.txt -T application/json http://0.0.0.0:5000/b/embedding

条件处理每条请求所用时间(均值)90%时间 
不用gunicorn

9.918ms

121

 
使用gunicorn:work=2

54ms

929

 

看到这,有点怀疑gunicorn的作用了,适得其反了。晚上查了一些gunicorn配置的优化,解决了这个性能 问题,并提速30%+。接下来看看什么原因导致服务性能下降,然后这个问题的解决方案是什么。

2.为什么会有“慢客户端行为”带来的服务性能降低问题?

[1]服务器和客户端的通信,我们简略的分为三个部分:request,request handling,和response,即客户端向服务器发起请求,服务器端响应并处理请求,和将请求结果返回客户端,这三个过程。

通常,request handling这部分即服务端的计算,拼的是服务器的性能,处理是比较高效和稳定的,而request和response部分,影响因素比较多,如果这三个过程放到同一个进程中同步处理,如果request和response部分耗时比较多,会使计算资源被占据并无法及时释放,导致计算资源无法有效利用,降低服务器的处理能力。

上述“慢客户端行为”,指的就是request(或response)部分耗时比较多的情况,Gunicorn恰好会把上面三个过程放到同一个进程中,当出现“慢客户端行为”时,效率很低:

Gunicorn 是一个pre-forking的软件,这类软件对低延迟的通信,如负载均衡或服务间的互相通信,是非常有效的。但pre-forking系统的不足是,每个通信都会独占一个进程,当向服务器发出的请求多于服务器可用的进程时,由于服务器端没有更多进程响应新的请求,其响应效率会降低。

对于Web网站或服务而言,由于request和response延时是不可控的,我们需要在考虑处理高延迟客户端请求的情况。这些请求会占据服务器端的进程。当慢客户端直接与服务通信时,由于慢客户端请求会占据进程,可用于处理新请求的进程就会减少,如果有很多慢客户端请求把所有进程都占据后,新的请求只能等待有进程被释放掉后,得到响应。另外,如果应用希望有更高的并发,服务器与客户端的通信要更高效,异步的通信会比同步的通信更有效。

3.gunicorn配置优化

三种并发方式:

一、workers 模式,又名 UNIX 进程模式

每个 worker 都是一个加载 Python 应用程序的 UNIX 进程。worker 之间没有共享内存。建议的 workers 数量是 (2*CPU)+1。对于一个双核(两个CPU)机器,5 就是建议的 worker 数量。

gunicorn --workers=5 main:app

当然也可以将--workers=5写到一个配置文件中,如下:
# gunicorn.py

workers = 2
timeout = 60
bind = '0.0.0.0:9501'
worker_class = 'gevent'
worker_connections = 1000

max_requests = 50000
max_requests_jitter = 2

起服务命令:
gunicorn -c gunicorn.py run:app
其中-c表示传入配置文件
run表示你flask服务所在的文件名
app表示你的flask服务实例

二、多线程[优胜之选]

Gunicorn 还允许每个 worker 拥有多个线程。在这种场景下,Python 应用程序每个 worker 都会加载一次,同一个 worker 生成的每个线程共享相同的内存空间。

为了在 Gunicorn 中使用多线程。我们使用了 threads 模式。每一次我们使用 threads 模式,worker 的类就会是 gthread:

gunicorn --workers=5 --threads=2 run:app

最大的并发请求数就是 worker * 线程,也就是10。

在使用 worker 和多线程模式时建议的最大并发数量仍然是(2*CPU)+1。

因此如果我们使用四核(4 个 CPU)机器并且我们想使用 workers 和多线程模式,我们可以使用 3 个 worker 和 3 个线程来得到最大为 9 的并发请求数量。

gunicorn --workers=3 --threads=3 run:app

三、“伪线程”

有一些 Python 库比如(gevent 和 Asyncio)可以在 Python 中启用多并发。那是基于协程实现的“伪线程”。

Gunicrn 允许通过设置对应的 worker 类来使用这些异步 Python 库。

这里的设置适用于我们想要在单核机器上运行的gevent:

gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 run:app
worker-connections 是对于 gevent worker 类的特殊设置。

(2*CPU)+1 仍然是建议的workers 数量。因为我们仅有一核,我们将会使用 3 个worker。

在这种情况下,最大的并发请求数量是 3000。(3 个 worker * 1000 个连接/worker)

并发 vs. 并行

  • 并发是指同时执行 2 个或更多任务,这可能意味着其中只有一个正在处理,而其他的处于暂停状态。
  • 并行是指两个或多个任务正在同时执行。

在 Python 中,线程和伪线程都是并发的一种方式,但并不是并行的。但是 workers 是一系列基于并发或者并行的方式。

参考:

1.服务性能降低:https://www.zhihu.com/question/38528616

2.gunicorn的三种并发方式:https://zhuanlan.zhihu.com/p/286081773

3.unix+gunicorn的作用:https://www.cnblogs.com/dion-90/articles/8530451.html

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 可以使用 Python Flask 搭建 web 服务器和客户端,下面是一个简单的示例: 1. 安装 flask 包:pip install flask 2. 创建一个名为 app.py 的文件,并在其中编写 flask 代码 3. 在终端中运行 python app.py 命令,启动服务器 4. 打开浏览器,输入 http://localhost:5000/ 即可访问服务器及客户端 ### 回答2: 搭建 Python Flask Web 服务器和客户端的步骤如下: 1. 安装 Python:首先需要在计算机上安装 Python。可以从官方网站 (https://www.python.org/) 下载并安装适合你操作系统的 Python 版本。 2. 安装 Flask:使用命令行或终端运行以下命令安装 Flask 框架:$ pip install flask 3. 引入 Flask:在 Python 脚本中引入 Flask 模块:from flask import Flask 4. 创建 Flask 应用:使用 Flask 类创建一个应用对象,并将其赋值给一个变量,例如:app = Flask(__name__) 5. 创建路由:使用装饰器语法定义不同的路由。路由是指应用中的不同 URL 与对应的函数之间的映射关系。例如:@app.route('/') def home(): return 'Welcome to My Python Flask Web Server!' 6. 运行服务器:在程序的末尾添加以下代码,以在本地主机上运行 Flask 服务器:if __name__ == '__main__': app.run() 7. 测试服务器:在命令行或终端中运行 Python 脚本,如:$ python your_script.py。将会显示服务器正在运行的信息。 以上是搭建 Python Flask Web 服务器的步骤。接下来,可以编写客户端代码来与服务器进行通信。客户端可以使用 requests、urllib 或其他 HTTP 请求库进行发送 GET、POST 等请求,并接收服务器响应。 例如,使用 requests 库发送 GET 请求: import requests url = 'http://localhost:5000/home' response = requests.get(url) print(response.text) 这是一个简单的例子,展示了如何使用 Python Flask 搭建 Web 服务器和编写客户端代码来与服务器进行通信。具体的实现方式还可以根据实际需求进行调整和扩展。 ### 回答3: Python flask 是一个使用 Python 编写的轻量级 Web 框架,其简洁易用的特点使得搭建 Web 服务器及客户端变得非常方便。 首先,我们需要安装 Flask 模块。可以使用 pip 命令来安装,如下所示: ``` pip install flask ``` 在 Python 脚本中,我们需要导入 Flask 模块,并创建一个应用实例,如下所示: ```python from flask import Flask app = Flask(__name__) ``` 接下来,我们可以为应用添加路由和视图函数。路由是指 URL 和视图函数之间的映射关系。例如,我们可以为根路径 "/" 添加一个视图函数,如下所示: ```python @app.route('/') def hello_world(): return 'Hello, World!' ``` 在视图函数中,我们可以使用 return 语句返回给客户端一个字符串作为响应。 最后,我们需要运行应用来启动 Web 服务器。可以在脚本的末尾添加以下代码,来指定服务器运行的 IP 地址和端口号: ```python if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` 这样,我们就完成了一个简单的 Flask Web 服务器的搭建。 对于客户端,我们可以使用浏览器作为客户端来访问刚刚搭建的 Web 服务器。只需要在浏览器中输入服务器的 IP 地址和端口号,例如 "http://127.0.0.1:5000/",即可访问服务端返回的结果。 另外,我们也可以使用 Python 的 requests 模块作为客户端,通过发送 HTTP 请求来获取服务器的响应。可以使用以下代码示例来发送 GET 请求: ```python import requests url = 'http://127.0.0.1:5000/' response = requests.get(url) print(response.text) ``` 以上就是使用 Python Flask 搭建 Web 服务器及客户端的简要步骤。通过 Flask,我们可以方便地搭建出一个满足特定需求的 Web 应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值