高并发Flask服务部署

AI模型持久化

OOP:

利用面向对象思想,实现算法在内存上的实例化持久化。即一次模型加载,多次请求调用。

class ocr_infer_class(threading.Thread):

    def __init__(self, input_queue, output_queue):
super().__init__()
logger.info("Model Init Start ...")
# YOLO Needed
self.yolo_model_def = os.path.join("../config", "yolov3.cfg")
self.yolo_weights_path = os.path.join("../checkpoints", "yolo.pth") # OCR Needed
self.ocr_weights_path = os.path.join("../checkpoints", "ocr.h5") # 初始化队列
self.input_queue = input_queue
self.output_queue = output_queue # allow growth
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
self.graph = tf.get_default_graph()
self.sess = tf.Session(config=config) # 初始化模型并加载权重
self.yolo_init()
# 初始化OCR
self.ocr_init() def yolo_init(self):
# load model
logger.info("YOLO Init Success ...") def ocr_init(self):
with self.graph.as_default():
with self.sess.as_default():
# load model
logger.info("OCR Init Success ...")

Thread+Queue

利用thread和queue实现请求监听

# 接收端
# 循环监听input_queue,一旦有数据就执行推理动作
def run(self):
while True:
try:
data = self.input_queue.get(True, 2000) # 监听获取input_queue中的数据
except queue.Empty as e: # 没有数据
logger.info('waiting for request...')
else:
# 获取数据后进行推理
image = data[0]
image_name = data[1] # 推理代码
result = self.get_detect_result(image, image_name,
height=image.shape[0], width=image.shape[1]) # 推理完毕后将结果放到output_queue中
self.output_queue.put(result) ################################################################################################# # 发送端
# 将请求数据通过request拿到后,put到被监听的queue中。
def get_result(self, image, image_name):
# 向被监听queue中put数据,触发推理动作
self.input_queue.put((image, image_name), )
logger.info("Geting Request ...")
# 推理完毕后会向output_queue中put数据
res = self.output_queue.get() return res

一些名词解释

高并发

​ 并发是OS的一个概念,指一段时间内多任务交替执行的现象。高并发泛指大流量、高请求量的业务场景;如双十一秒杀、春运抢票

  • 度量指标QPS、TPS、RT、并发数

    ​ QPS:Queries Per Second意思是“每秒查询率”,服务器在规定时间内处理多少流量。

    ​ TPS:Transactions Per Second意思是“每秒事务量”。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。

    ​ RT: Response Time,客户端发起请求到收到服务器响应结果的时间。直接反映了系统的快慢

    ​ 并发数: 系统同时能处理的请求数量,反应了系统的负载能力。

    ​ 吞吐量: 即承压能力。与request对CPU、IO的消耗等等紧密关联。单个request 对CPU消耗越高,外部系统接口、IO速度越慢,系统吞吐能力越低,反之越高。

  • 实现高并发的手段

    • 扩充硬件。更多核心更高主频更大存储空间更多带宽

    • 优化软件。改进架构、应用多线程、协程、更快的数据结构等

    • 架构分层、服务拆分、微服务解耦等。通过分布式集群和计算实现

高可用

​ 通过设计减少系统不能提供服务的时间。如果一个系统能够一直提供服务,那么这个可用性则是百分之百,如keepalived+Nginx实现的双机热备方法,当一台Nginx服务器宕机时,另一台顶上

高性能

​ 程序处理速度越快,所占内存越少,cpu占用率越低,性能越高

并发与并行

  • 并发:同时执行多个任务,但可能一个正在执行,另一个已暂停或结束。
  • 并行:多个任务同时执行

Flask

Flask是一个同步的Web框架,可以实现简易的web服务,但处理请求的时候是以单进程的方式,当同时访问的人数过多时,服务就会出现阻塞的情况。

​ 优点:易调试、可以很快的实现web server interface。

​ 缺点:自带的web server不稳定,无法承受大量并发请求。

WSGI

Web Server Gateway interface,服务器网关接口,是web服务器与web程序/框架 之间的通用接口。是一种协议,一种规范。用于解决众多web 服务器和web程序/框架之间的兼容性问题。

Gunicorn

What's Gunicorn?

Gunicorn是一个实现了WSGI协议的HTTP 服务器。类似的还有uWSGI、Gevent、Proxy setups等。

What's pre-fork?

可以采用pre-fork的方式提前准备多个子进程用于承载请求。实现了接收并处理并发请求。

安装Gunicorn

pip install gunicorn -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
# 安装异步worker支持的三方库
pip install gevent eventlet greenlet

配置Gunicorn

$ vim gunicorn.conf
bind = ":5000"
workers = 2 # 推荐核数*2+1发挥最佳性能
worker_class = 'gevent' # 除协程外,还有sync异步等等
threads = 1
worker_connections = 2000
timeout = 600 # 深度学习模型加载比较耗时,设长一点
reload = True
daemon = False accesslog = '../logs/access.log'
errorlog = '../logs/error.log'
loglevel = 'debug'

启动Gunicorn

# flask运行的入口文件为Flask_App.py,Flask实例名称为app
# 利用配置文件,启动一个主进程,两个子进程
$ gunicorn -c gunicorn.conf Flask_APP:app

请求实例

Gunicorn pre-fork了两个Flask进程,对外端口为5000,我们请求容器映射的 30006->5000/tcp

至此已经利用面向对象+线程+队列+Gunicorn实现了一个持久化的、可以处理并发请求的web服务。但HTTP 服务器性能还不够,

Nginx

正向代理与反向代理

正向代理:

​ 代理服务器替客户端请求访问不到的资源并返回(中介)

用处:

  • 突破访问限制(梯子)
  • 提升访问速度,一个客户端请求过的内容可能会缓存下来,另一个请求时直接发送。
  • 隐藏客户端真实IP,避免受攻击

反向代理:

​ 代理服务器接收Internet上的链接请求,然后将请求转发给内部网络上的服务器,并将其返回的结果再返回给Internet上请求链接的客户端。此时代理服务器的行为就叫做反向代理。(二房东)

用处:

  • 对客户端隐藏服务器真实IP
  • 负载均衡,代理服务器做反向代理前,会根据所有真实服务器的负载情况,决定将客户端的请求分发到哪台服务器上
  • 提升访问速度,同正向代理时一样,可以缓存一些东西,客户端请求时直接返回,如一些静态文件
  • 提供安全保障。可以用作防火墙,提供对web攻击的防护、加密服务器等

What's Nginx?

更强的HTTP 服务器,对外界请求做反向代理,能缓存一些静态文件提升访问速度的同时,还能做负载均衡,减轻服务器压力,并能提高服务器安全性。

​ 使用nginx来转发gunicorn服务。为什么要在gunicorn之上再加层nginx呢?一方面nginx可以补充gunicorn在某些方面的不足,如SSL支持、高并发处理负载均衡处理等,另一方面如果是做一个web网站,除了服务之外,肯定会有一些静态文件需要托管,这方面也是nginx的强项

Nginx 安装

apt upgrade && apt install nginx

Nginx配置

$ vim /etc/nginx/sites-available/default
# 修改对外端口
server {
listen 8000 default_server;
listen [::]:8000 default_server;
# 添加反向代理服务
location / {
# 这一行记得注掉,因为我们没有缓存静态文件,只是一个请求接口
# try_files $uri $uri/ =404; # 要转发的服务为本地5000端口的gunicorn服务
proxy_pass http://0.0.0.0:5000/;
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;
}

Nginx启动

/etc/init.d/nginx start

请求实例

Nginx代理了5000端口的gunicorn服务,对外端口为8000,映射到容器外为30007。

利用ab 进行压力测试

What's ab?

ApacheBench(ab),命令使用简单,效率高,统计信息完善,施压机器内存压力小。是在unix机器上推荐的压测工具。

ab的安装

apt-get install apache2-utils

ab的命令选项

option 含义
-r 当接收到socket错误的时候ab不退出
-t 发送请求的最长时间
-c 并发数,一次构造的请求数量
-n 发送的请求数量
-p postfile,指定包含post数据的文件
-T content-type,指定post和put发送请求时请求体的类型

Flask服务的并发测试

单纯的Flask 服务时, 设置60s超时,1k并发,总请求10w,60s超时

$ ab -r -t 60 -c 1000 -n 100000 -p /workspace/pressure_test/post_data.txt -T 'application/json' http://127.0.0.1:8705/id_recognition

This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Finished 44442 requests Server Software: Werkzeug/2.0.1
Server Hostname: 127.0.0.1
Server Port: 8705 Document Path: /id_recognition
Document Length: 78 bytes Concurrency Level: 1000
Time taken for tests: 60.000 seconds
Complete requests: 44442
Failed requests: 2790
(Connect: 0, Receive: 930, Length: 930, Exceptions: 930)
Total transferred: 10312344 bytes
Total body sent: 7696691010
HTML transferred: 3393936 bytes
Requests per second: 740.70 [#/sec] (mean)
Time per request: 1350.080 [ms] (mean)
Time per request: 1.350 [ms] (mean, across all concurrent requests)
Transfer rate: 167.84 [Kbytes/sec] received
125271.12 kb/s sent
125438.96 kb/s total Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 620 2456.7 0 31086
Processing: 0 458 2627.2 175 53163
Waiting: 0 235 613.7 173 26668
Total: 142 1079 3959.1 176 54166 Percentage of the requests served within a certain time (ms)
50% 176
66% 186
75% 205
80% 1172
90% 1395
95% 3215
98% 8853
99% 17271
100% 54166 (longest request)

Flask+Gunicorn服务的并发测试

$ ab -r -t 60 -c 1000 -n 100000 -p /workspace/pressure_test/post_data.txt -T 'application/json' http://127.0.0.1:5000/id_recognition

This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Finished 48453 requests Server Software: gunicorn
Server Hostname: 127.0.0.1
Server Port: 5000 Document Path: /id_recognition
Document Length: 96 bytes Concurrency Level: 1000
Time taken for tests: 60.000 seconds
Complete requests: 48453
Failed requests: 706
(Connect: 0, Receive: 193, Length: 320, Exceptions: 193)
Total transferred: 12273915 bytes
Total body sent: 8364221730
HTML transferred: 4620768 bytes
Requests per second: 807.55 [#/sec] (mean)
Time per request: 1238.315 [ms] (mean)
Time per request: 1.238 [ms] (mean, across all concurrent requests)
Transfer rate: 199.77 [Kbytes/sec] received
136136.24 kb/s sent
136336.01 kb/s total Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 747 1805.0 1 31078
Processing: 0 417 2215.4 171 53472
Waiting: 0 312 994.1 169 33853
Total: 69 1164 2977.1 193 54476 Percentage of the requests served within a certain time (ms)
50% 193
66% 1157
75% 1180
80% 1195
90% 3147
95% 3390
98% 7197
99% 12255
100% 54476 (longest request)

Flask+Gunicorn+Nginx服务的并发测试

$ ab -r -t 60 -c 1000 -n 100000 -p /workspace/pressure_test/post_data.txt -T 'application/json' http://127.0.0.1:8000/id_recognition

This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Finished 79043 requests Server Software:
Server Hostname: 127.0.0.1
Server Port: 8000 Document Path: /id_recognition
Document Length: 0 bytes Concurrency Level: 1000
Time taken for tests: 60.006 seconds
Complete requests: 79043
Failed requests: 100893
(Connect: 0, Receive: 21865, Length: 46413, Exceptions: 32615)
Non-2xx responses: 1850
Total transferred: 12631524 bytes
Total body sent: 13739835630
HTML transferred: 4650808 bytes
Requests per second: 1317.26 [#/sec] (mean)
Time per request: 759.154 [ms] (mean)
Time per request: 0.759 [ms] (mean, across all concurrent requests)
Transfer rate: 205.57 [Kbytes/sec] received
223608.53 kb/s sent
223814.10 kb/s total Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 8 45.2 1 1009
Processing: 0 693 1742.3 177 32773
Waiting: 0 686 1744.0 176 32773
Total: 0 701 1745.3 179 32774 Percentage of the requests served within a certain time (ms)
50% 179
66% 209
75% 604
80% 1190
90% 1499
95% 3219
98% 7186
99% 7362
100% 32774 (longest request)

至此,我们利用Gunicorn+Nginx实现了一个可做负载均衡,具有反向代理功能的高并发Web服务。但意外停止怎么办?

我们利用supervisor实现进程管理,对Nginx和Gunicorn服务做监听,掌控它们的启动、停止、重启

Supervisor

supervisor是一个用python语言编写的进程管理工具,它可以很方便的监听、启动、停止、重启一个或多个进程。当一个进程意外被杀死,supervisor监听到进程死后,可以很方便的让进程自动恢复

安装supervisor

# 安装supervisor的方式很多种,现在新版本的supervisor也原生支持python3,但apt安装的版本配置更简单,坑少,推荐
apt-get install supervisor # 启动、停止、重启
$ /etc/init.d/supervisor start / stop / restart

配置Gunicorn服务

# 测试是否成功方法,在directory下执行command,如果不报错就行
$ vim /etc/supervisor/conf.d/gunicorn.conf
[program:gunicorn_flask]
command=gunicorn -c gunicorn.conf Flask_App:app
directory=/workspace/Flask/
autostart=true
autorestart=true
user=root
redirect_stderr=true

配置Nginx服务

$ vim /etc/supervisor/conf.d/nginx.conf
[program:nginx_flask]
command=/usr/sbin/nginx -g 'daemon on;'
autostart=true
autorestart=true
user=root
redirect_stderr=true

查看supervisor的日志

cat /var/log/supervisor/supervisord.log

启动测试

先关闭Gunicorn和Nginx服务。

$ kill -9 $(ps -ef| egrep 'gunicorn|nginx' | grep -v grep | awk '{print $2}')
$ ps ax | egrep 'gunicorn|nginx'

利用supervisor启动Gunicorn和Nginx

$ /etc/init.d/supervisor start
$ ps ax | egrep 'gunicorn|nginx'

请求测试Nginx的代理服务

重启测试

大工告成!感谢阅读

高并发Flask服务部署的更多相关文章

  1. 转---高并发Web服务的演变——节约系统内存和CPU

    [问底]徐汉彬:高并发Web服务的演变——节约系统内存和CPU 发表于22小时前| 4223次阅读| 来源CSDN| 22 条评论| 作者徐汉彬 问底Web服务内存CPU并发徐汉彬 摘要:现在的Web ...

  2. IM即时通讯设计 高并发聊天服务:服务器 + qt客户端(附源码)

    来源:微信公众号「编程学习基地」 目录 IM即时通信程序设计 IM即时通讯 设计一款高并发聊天服务需要注意什么 如何设计可靠的消息处理服务 什么是粘包 什么是半包 解决粘包和半包 IM通信协议 应用层 ...

  3. 高并发Web服务的演变:节约系统内存和CPU

    一.越来越多的并发连接数 现在的Web系统面对的并发连接数在近几年呈现指数增长,高并发成为了一种常态,给Web系统带来不小的挑战.以最简单粗暴的方式解决,就是增加Web系统的机器和升级硬件配置.虽然现 ...

  4. 高并发 Web 服务的演变:节约系统内存和 CPU

    本文内容 越来越多的并发连接数 Web 前端优化,降低服务端压力 节约 Web 服务端的内存 节约 Web 服务器的 CPU 小结 一,越来越多的并发连接数 现在,Web 系统面对的并发连接数呈现指数 ...

  5. (转)高并发Web服务的演变——节约系统内存和CPU

    一.越来越多的并发连接数 现在的Web系统面对的并发连接数在近几年呈现指数增长,高并发成为了一种常态,给Web系统带来不小的挑战.以最简单粗暴的方式解决,就是增加Web系统的机器和升级硬件配置.虽然现 ...

  6. 【WEB】高并发Web服务的演变-节约系统内存和CPU

    目前主流浏览器通常可以存在2-6个并发. 连接和请求,占据了服务器的大量CPU和内存等资源.在资源数目超过100+的网站页面中,使用更多的下载连接,非常有必要. 缓解“高并发”的压力的手段. 一. W ...

  7. 高并发WEB服务的演变

    一.越来越多的并发连接数 现在的Web系统面对的并发连接数在近几年呈现指数增长,高并发成为了一种常态,给Web系统带来不小的挑战.以最简单粗暴的方式解决,就是增加 Web系统的机器和升级硬件配置.虽然 ...

  8. 提高Django高并发性的部署方案(Python)

    方案: nginx + uWSGI 提高 Django的并发性        1. uWSGI :                 uWSGI是一个web服务器,实现了WSGI协议.uwsgi协议.h ...

  9. 高并发Web服务的演变——节约系统内存和CPU

    节约系统内存和CPU http://www.csdn.net/article/2015-02-12/2823952 Web系统大规模并发——电商秒杀与抢购 http://www.csdn.net/ar ...

随机推荐

  1. [Web] 通用轮播图代码示例

    首先是准备好的几张图片, 它们的路径是: "img/1.jpg", "img/2.jpg", "img/3.jpg", "img/ ...

  2. hdu4267线段树段更新,点查找,55棵线段树.

    题意:      给你N个数,q组操作,操作有两种,查询和改变,查询就是查询当前的这个数上有多少,更改是给你a b k c,每次从a到b,每隔k的数更改一次,之间的数不更改,就相当于跳着更新. 思路: ...

  3. POJ 3621 最优比率生成环

    题意:      让你求出一个最优比率生成环. 思路:      又是一个01分化基础题目,直接在jude的时候找出一个sigma(d[i] * x[i])大于等于0的环就行了,我是用SPFA跑最长路 ...

  4. hdu4982 暴搜+剪枝(k个数和是n,k-1个数的和是平方数)

    题意:       给你两个数n,k问你是否怎在这样一个序列:      (1)这个序列有k个正整数,且不重复.      (2)这k个数的和是n.      (3)其中有k-1个数的和是一个平方数. ...

  5. ASLR 的关闭与开启(适用于 Windows7 及更高版本)

    ASLR 是一种针对缓冲区溢出的安全保护技术,通过对堆.栈.共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的的一种技术 有的时候 ...

  6. 【Android Jetpack高手日志】DataBinding 从入门到精通

    前言 DataBinding 数据绑定库是 Android Jetpack 的一部分,借助该库可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源.我个人觉得,使用 DataBin ...

  7. 学习Python一年,这次终于弄懂了浅拷贝和深拷贝

    官方文档:copy主题 源代码: Lib/copy.py 话说,网上已经有很多关于Python浅拷贝和深拷贝的文章了,不过好多文章看起来还是决定似懂非懂,所以决定用自己的理解来写出这样一篇文章. 当别 ...

  8. Day009 Arrays类

    Arrays类 数组的工具类java.util.Arrays 由于数组对象本身并没有什么方法可以供我们调用,但Api中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作. 查 ...

  9. left join 后用 on 还是 where,区别大了!

    前天写SQL时本想通过 A left B join on and 后面的条件来使查出的两条记录变成一条,奈何发现还是有两条. 后来发现 join on and 不会过滤结果记录条数,只会根据and后的 ...

  10. 从 demo 到生产 - 手把手写出实战需求的 Flink 广播程序

    Flink 广播变量在实时处理程序中扮演着很重要的角色,适当的使用广播变量会大大提升程序处理效率. 本文从简单的 demo 场景出发,引入生产中实际的需求并提出思路与部分示例代码,应对一般需求应该没有 ...