我有一个非常简单的API,使用Flask开发,我试图在Amazon Elastic Beanstalk上部署。我能够在没有太多麻烦的情况下启动并运行API,并且当我一次发送一个请求时它工作正常。但是,当我立刻发出几个请求时,我遇到了麻烦。
API有一个终点,其目的是向各种其他应用程序公开预测模型。它将JSON作为POST请求的一部分发送的数据,并返回结果以及一些元数据。
该模型是一个经过预先训练的scikit-learn分类器,我已经序列化并存储在Amazon S3上,因此Web应用程序可以访问它。
以下是应用程序代码的简化版本:
from __future__ import division
from datetime import datetime
import joblib
import gzip
import numpy as np
from StringIO import StringIO
from flask import Flask, request, json
from boto import connect_s3
application = Flask('myapp')
def get_model():
s3 = connect_s3()
b = s3.get_bucket('mybucket')
k = b.get_key('path/to/model/trained_model.gz')
f = gzip.GzipFile(fileobj=StringIO(k.get_contents_as_string()))
mdl = joblib.load(f)
return mdl
mdl = get_model()
def get_input_from_json(input_json):
return np.array(
[[
input_json['field1'],
input_json['field2'],
input_json['field3'],
...
]]
)
@application.route('/predict', methods=['POST'])
def predict():
X = get_input_from_json(request.json)
result = mdl.predict(X)
out = dict(
result=result,
eval_time=datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
)
return json.dumps(out)
if __name__ == "__main__":
application.debug = True
application.run()
如前所述,当我发送个别请求,甚至数百个请求时,我已经部署并运行正常。但是,如果我同时发送多个请求,请求将失败并显示504错误。
检查Web服务器日志我发现了一些错误,例如End of script output before headers: application.py
。我发现其默认配置中的wsgi与包含C扩展(如scipy)的模块不兼容,并且您必须在wsgi.conf配置文件中设置WSGIApplicationGroup {%Global}
。在http://djm.io/deploying-scipy-into-aws-elastic-beanstalk/之后我修改了.ebextensions以将此行添加到wsgi.conf中,但它根本没有帮助。我一直在谷歌搜索这个问题的其他可能原因,但到目前为止空手而归。
我可以看到的一个潜在问题是mdl
对象位于predict
函数范围之外。这是我从S3上存储的文件反序列化的训练有素的scikit-learn模型。我无法为每个请求在predict
函数内部加载模型;它需要太长时间,请求最终超时。这就是为什么我预先加载模型并让它在应用程序运行时保持不变的原因。但我可以想象,如果必须同时通过多次执行predict
函数来访问此对象,我可能会遇到问题。麻烦的是,我不知道如何诊断这是否真的是我的问题,以及我是否应该如何解决它。
那么在全球范围内定义模型是否有效,就像我在这里所做的那样?如果没有,我怎么能以更真实的无状态方式去做呢?或者还有其他一些问题吗?
谢谢!