随手找的一些模型部署简单例子.
uWSGI
uWSGI, pronounced “mu wiz gee” (u or $\mu$ whiskey), is a Web Server Gateway Interface (WSGI) server implementation that is typically used to run Python web applications.
可以参考 uWSGI - Full Stack Python 收集的资源. Full Stack Python 是很好的资源站.
Gunicorn
Green Unicorn, commonly shortened to “Gunicorn”, is a Web Server Gateway Interface (WSGI) server implementation that is commonly used to run Python web applications.
Use Gunicorn, unless you are deploying on Windows, in which case use mod_wsgi.
uWSGI 很多功能与 Nginx 等部件重复, 文档也很杂乱 (开发者承认很难写). Gunicorn 简单效果好.
- Antonis Christofides. (2020). Which WSGI server should I use?
gevent
gevent is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev or libuv event loop.
A monkey patch (also spelled monkey-patch, MonkeyPatch) is a way to extend or modify the runtime code of dynamic languages (e.g. Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.) without altering the original source code.
- 罗辑. (2018). 有哪些应用场景适合用 python 的 gevent 来完成?
- 罗辑. (2018). Python 黑魔法: greenlet
Ngnix
Nginx, pronounced “engine-X”, is the second most common web server among the top 100,000 websites. Nginx also functions well as a reverse proxy to handle requests and pass back responses for Python WSGI servers or even other web servers such as Apache.
Flask
Flask is a Python web framework built with a small core and easy-to-extend philosophy.
基本用法没什么好说的. 此外有个自动生成 Swagger UI 的包 Flask-RESTX. Flask-RESTX is a community driven fork of Flask-RESTPlus (后者很久没维护了, 前者也有一段时间不怎么维护了).
部署到生产时官方 tutorial 用了 Waitress; 这里 介绍了各种常见 WSGI server 部署 Flask 的例子.,
- 一个并发的网站, Tornado 与 Flask 应该选哪一个?
- Flask - Full Stack Python
- python - What is an ‘endpoint’ in Flask? - Stack Overflow
FastAPI
Celery
Celery is a task queue implementation for Python web applications used to asynchronously execute work outside the HTTP request-response cycle.
异步基本就用这个库. Celery 命名 来源 于, 它把数据喂给 RabbitMQ.
把应用迁移到使用 Celery 不用改什么代码, 工作量主要在配置上.
一些资源 (Show more »)
- How to Use Celery and RabbitMQ with Django is a great tutorial that shows how to both install and set up a basic task with Django.
- Celery - Best Practices explains things you should not do with Celery and shows some underused features for making task queues easier to work with.
- Celery Best Practices is a different author's follow up to the above best practices post that builds upon some of his own learnings from 3+ years using Celery.
- 备用: Python 分布式调度框架 Celery 踩坑日记
其他看到的
- python - Why use Celery instead of RabbitMQ? - Stack Overflow
- 5 tips for writing production-ready Celery tasks - Wolt Blog
- Production-ready Celery configuration - Progress Story
进一步解释 Celery 机制
除了一开始的 tutorial, 官方 userguide 建议先看 tasks.
Celery 启动后先注册任务, 可以用 --loglevel=DEBUG
, 搜索 tasks, 看任务有没有注册, 注册了哪些 (autodiscover_tasks
中可以指定搜索路径). 在代码中实际使用时, 函数路径必须和注册的任务名相同 (x.y.z, 注意相对 import).
其他
Flask-RESTX demo
需要注意的是, 如果开了 .expect(validate=True)
, 发送不合法的请求后, Swagger UI 上不会有任何提示. 这是 Swagger UI 的一个 “bug”, 见这个 issue.
import flask
import flask_restx
from flask import request
from flask_restx import fields
app = flask.Flask(__name__)
api = flask_restx.Api(app=app, title='app title', version='2.3.3', description='app desc')
CONFERENCES_DESC = """
Conference operations
Markdown is supported.
"""
ns_conf = api.namespace(name='conferences', description=CONFERENCES_DESC)
model_conf_input = ns_conf.model(
name='my_model',
model={
'name': fields.String(
example='C7', description='name whatever', title='field title',
min_length=1, max_length=10, pattern=r'[A-Z][0-9]', required=True
),
# the default example is the first element of the enum argument ('A' in this case)
'type': fields.String(enum=['A', 'B', 'C']),
'nums': fields.List(
fields.Integer(min=0, max=100),
min_items=0, max_items=10, description='list of integers'
),
'bool': fields.Boolean(),
},
strict=True
)
model_conf_response = ns_conf.model(name='response', model={
'name': fields.String(description='haha'),
'nums': fields.List(fields.Integer())
})
@ns_conf.route("/")
class ConferenceList(flask_restx.Resource):
# `.doc(body=...)` or `.expect(...)` for input
# `.doc(model=...)` for response
@ns_conf.expect(model_conf_input, validate=True)
@ns_conf.param('payload', 'some description goes here', _in='body')
@ns_conf.response(200, 'Success', model_conf_response)
@ns_conf.response(400, 'Validation Error')
def post(self):
"""
random example
**markdown is also supported in docstring**
"""
name = request.json.get('name')
nums = request.json.get('nums')
return {
'name': name,
'nums': nums
}
@ns_conf.route("/<int:id>")
class Conference(flask_restx.Resource):
@ns_conf.doc(params={'id': 'An ID'})
def get(self, id):
return id
if __name__ == '__main__':
app.run(debug=True)
Memo
- Exadel AI Team. (2020). Deploying Multiple Machine Learning Models on a Single Server
- 模型压测: Locust (很简单)
- 测试工具 wrk