将算法部署成HTTP服务

算法工程师有时需要将模型部署在服务器上,然后根据定义好的接口向外部提供一个HTTP服务,使用户能够调用这一算法。下面记录一下使用Flask + Gunicorn的方案,以及其中涉及的一些知识点。

Gunicorn和Flask简介

Gunicorn是个啥,根据其官网定义:

  • 首先它是一个遵循WSGI协议的HTTP服务器。

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

WSGI又是啥? WSGI是Web Server Gateway Interface的缩写,翻译过来就是Web服务器网关接口。根据WIKI上的描述,它是Web服务器将请求转发到以Python语言编写的Web应用程序或框架的简单调用约定。像Nginx、Apache HTTP Server都是常见的Web服务器软件,而像Django、Pyramid、Flask、Web2py则是所谓的Web框架。

The Web Server Gateway Interface is a simple calling convention for web servers to forward requests to web applications or frameworks written in the Python programming language. The current version of WSGI, version 1.0.1, is specified in Python Enhancement Proposal (PEP) 3333.[4] WSGI was originally specified as PEP-333 in 2003.[5] PEP-3333, published in 2010, updates the specification for Python 3.

这里强烈推荐知乎文章《尝试理解Flask源码 之 搞懂WSGI协议》去了解上文所提及到的一些内容。这篇文章最后提到,虽然Flask是Web框架,但是它自带了服务器,而且这是一个WSGI服务器,只不过性能低,不支持高并发,只能用于测试。

  • 其次它是一个pre-fork worker模型

关于这点可以参考文章《程序员专享绿色独角兽Gunicorn,了解下》。所谓pre-fork就是在request到来之前,先fork出多个worker子进程用来负责处理请求。

Gunicorn使用方法

在Linux下安装好gunicorn后,通过下面的命令行就可以启动应用程序了。
gunicorn -c gunicorn_conf.py interface:app
其中gunicorn_conf.py是gunicorn的参数配置文件,第一个interface是要运行interface.py模块里的代码,第二个是指Flask应用的名字。下面举个简单的例子

# !/user/bin/env python3
# -*- coding:utf-8 -*-
# @File: interface.py
# @Author: Kang
# @Time: 2021/08/01 19:00
from flask import Flask  
app = Flask(__name__)  

@app.route('/test')  
def test():  
    return 'Test Finished' 

if __name__ == '__main__':  
    app.run() 

下面给出一个配置文件的样例

import os

# 监听端口设置
PORT_ENV = os.getenv("PORT_ENV", "8080")
bind = "0.0.0.0%s"%(PORT_ENV)
# 是否以守护进程启动, 默认为false
daemon = 'false'
# 进程/线程/工作模式设置
workers = 10
threads = 3
# worker_class = 'gevent'
worker_connections = 1000
pidfile = 'logs/gunicorn.pid'
# 请求连接相关设置
keep_alive = 5
timeout = 100000
limit_request_line = 8190
limit_request_field_size = 0
# 日志相关设置
accesslog = 'logs/gunicorn_access.log'
errorlog = 'logs/gunicorn_error.log'
loglevel = 'warning'

Gunicorn + Flask框架下实现简单异步返回

一般来说,客户会发送一个HTTP请求来获取算法服务。比如客户发送一张图片到服务器,希望服务器识别出这张图片是什么东西(算法模型来处理),然后将结果写入到数据库。如果不做异步返回处理,要等待计算完成程序才会返回一个"Task Finished"信号。现在我们希望程序接收到请求后,将任务放在后台运行,并返回一个"Task Scheduled"的信号。一个简单的方法是新开一个线程,将主要的计算任务放在该线程进行处理。当然,网上也有一些其它的方式可以参考,比如说Celery、Gunicorn的Gevent等。

from flask import Flask  
import threading
app = Flask(__name__)  

def core(arg1, arg2)
    ...

@app.route('/test')  
def test():  
    a1 = 1
    a2 = 2
    t = threading.Thread(target=core, daemon=None, args=(a1, a2))
    t.start()
    return 'Test Finished' 

if __name__ == '__main__':  
    app.run() 

关于threading.Thread()中的daemon参数。如果一个thread被设置成daemon=True,那么当main program退出时(或者说当所有non-daemon thread都结束退出时), daemon参数为True的thread会自动被kill掉。如果daemon不设置为True,那么即便主程序(其中一个thread)退出了,我们另外那个线程还会继续把它的任务做完。Daemon thread通常用在那些一直循环、自己不知道退出的情况下。
参考《Daemon Threads Explanation》
但是,这里的daemon参数和我们常说的daemon process有些细微差别。守护进程是一种脱离了终端、在后台运行的特殊进程,这使它能够避免被任何终端产生的信号打断。WIKI中的解释为

In multitasking computer operating systems, a daemon (/ˈdiːmən/ or /ˈdeɪmən/)[1] is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Traditionally, the process names of a daemon end with the letter d, for clarification that the process is in fact a daemon, and for differentiation between a daemon and a normal computer program. For example, syslogd is a daemon that implements system logging facility, and sshd is a daemon that serves incoming SSH connections.
In a Unix environment, the parent process of a daemon is often, but not always, the init process(PID=1). A daemon is usually created either by a process forking a child process and then immediately exiting, thus causing init to adopt the child process(一个父进程已经terminated的进程称为孤儿进程orphan process, 孤儿进程将由init进程收养), or by the init process directly launching the daemon. In addition, a daemon launched by forking and exiting typically must perform other operations, such as dissociating the process from any controlling terminal (tty). Such procedures are often implemented in various convenience routines such as daemon(3) in Unix.
Systems often start daemons at boot time that will respond to network requests, hardware activity, or other programs by performing some task. Daemons such as cron may also perform defined tasks at scheduled times.

posted @ 2021-09-11 23:28  渐渐的笔记本  阅读(740)  评论(0编辑  收藏  举报