美文网首页
Flask+UWSGI+Nginx提供在线预测服务

Flask+UWSGI+Nginx提供在线预测服务

作者: 王金松 | 来源:发表于2019-03-12 17:37 被阅读0次

    背景

    之前一直是通过tensorflow的cpu版本进行训练,工程化的时候需要把ckpt模型转换为.pb,然后继承到spark中运行。但是这样会有几个问题:

    1. 模型不能进行序列化,不能通过广播传递模型,也不能做唯一的加载,只能是对每个批次的数据进行预测的时候,在每个线程里面哦都要加载一次
    2. 每次加载模型时间都很长,并且检测的时候还是通过cpu,所以数据量小没什么问题,如果数据量太大,肯定会受影响

    之后有了gpu的机器,所以安装了tensorflow-gpu,参考tensorflow安装(GPU版本)。如果有了gpu,当然检测的时候希望也能通过gpu检测,所以有了这篇文章,通过Flask框架提供web接口,然后远程调用接口进行预测。

    Flask

    Flask安装
    pip install flask
    
    Flask代码
    [admin@A01-R15-I47-118-0825868 http-cnn-rnn]$ pwd
    /export/src/http-cnn-rnn
    [admin@A01-R15-I47-118-0825868 http-cnn-rnn]$ vim rest.py 
    
    from flask import Flask,request,jsonify
    import json
    from cnn_model import TCNNConfig, TextCNN
    from predict import CnnModel
    app = Flask(__name__)
    
    app.config['JSON_AS_ASCII'] = False
    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #16MB
    cnn_model = CnnModel()
    
    @app.route("/predict", methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            data = request.get_data().decode('utf-8')
            return predict(data)
        elif request.method == 'GET':
            #data = request.form.get('data')
            data = request.args.get('data')
            #return ">>>>"
            return predict(data)
        else:
            return jsonify({"not support":"400"})
    
    
    def predict(data):
        data = json.loads(data)
        ret = {}
        for url in data:
            predict_ret = cnn_model.predict(url)
            ret[url] = predict_ret
        ret = jsonify(ret)
        return ret
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0',port=8081, debug=False, threaded=True)
    

    UWSGI

    安装
    pip install uwsgi
    
    配置
    • uWSGI是一个由python实现的web容器,可以兼容性比较好地发布Django,Flask等pythonweb框架的应用。因为本质上来说uwsgi是python的一个模块,所以可以用pip install uwsgi直接来安装它。
    • 安装完成之后可以在一个合适的目录建立一个uwsgi服务器的配置文件。比如我选择在项目的根目录建立了一个uwsgiconfig.ini的文件。顺便一提,除了ini格式的配置,uwsgi还支持json,xml等多种多样的配置格式。这里以ini格式为例
    [uwsgi]
    socket = /export/src/http-cnn-rnn/uwsgi.sock
    pythonpath = /export/src/http-cnn-rnn
    module = rest
    wsgi-file = /export/src/http-cnn-rnn/rest.py
    callable = app
    processes = 1
    threads = 2
    daemonize = /export/src/http-cnn-rnn/server.log
    
    对配置的简单说明
    • pythonpath指出了项目的目录,module指出了项目启动脚本的名字而紧接着的wsgi-file指出了真正的脚本的文件名。callable指出的是具体执行.run方法的那个实体的名字,一般而言都是app=Flask(name)的所以这里是app。processes和threads指出了启动uwsgi服务器之后,服务器会打开几个并行的进程,每个进程会开几条线程来等待处理请求,显然这个数字应该合理,太小会使得处理性能不好而太大则会给服务器本身带来太大负担。daemonize项的出现表示把uwsgi服务器作为后台进程启动,项的值指向一个文件表明后台中的所有输出都重定向到这个日志中去
    • http-socket:使用的通讯协议,除了这个协议之外,还有http和socket,这三者的区别是,http和http-socket都是http协议,两者的区别我也没怎么分,官方文档推荐使用http-socket,socket就是uwsgi协议,官方解释是uwsgi协议通讯效率更高,这里我暂且先使用更加简单的http协议吧。另外如果用socket协议的话,nginx的配置会有所不同,后面会再说。
    uWSGI启动
    uwsgi --ini /export/src/http-cnn-rnn/uwsgiconfig.ini
    
    1. 执行之后会生成 /export/src/http-cnn-rnn/uwsgi.sock,这个需要在nginx.conf指定
    2. 以后通过nginx访问flask,flask的记录信息在daemonize的配置中,即/export/src/http-cnn-rnn/server.log
    开机自启动(可以不操作,忽略)
    $ vi /etc/rc.local
    /usr/local/bin/uwsgi -ini /var/www/demo/demo_uwsgi.ini
    

    Nginx安装

    安装依赖包
    • Nginx与Redis一样,都是C语言开发的,所以都需要在Linux上使用C语言编译后才能使用,所以得先安装用于编译的c环境
    sudo yum install -y gcc-c++
    sudo yum install -y pcre pcre-devel
    sudo yum install -y zlib zlib-devel
    sudo yum install -y openssl openssl-devel
    
    下载 Nginx&&解压

    下载地址:http://nginx.org/download/nginx-1.13.0.tar.gz

    wget http://nginx.org/download/nginx-1.13.0.tar.gz
    tar -zxvf nginx-1.13.0.tar.gz
    cd nginx-1.13.0
    

    编译安装

    $ ./configure --prefix=/usr/local/nginx 
    $ make
    $ sudo make install
    
     ./configure  --prefix=/usr/local/nginx  \
                  --sbin-path=/usr/local/nginx/sbin/nginx \
                  --conf-path=/usr/local/nginx/conf/nginx.conf \
                  --error-log-path=/var/log/nginx/error.log  \
                  --http-log-path=/var/log/nginx/access.log  \
                  --pid-path=/var/run/nginx/nginx.pid \
                  --lock-path=/var/lock/nginx.lock  \
                  --user=nginx \
                  --group=nginx
    

    我在执行的时候只是指定了 --prefix/--error-log-path/--http-log-path,主要原因是为了指定日志到一个比较大的磁盘

    查看nginx版本
    [admin@A01-R15-I47-121-0825870 sbin]$ pwd
    /usr/local/nginx/sbin
    [admin@A01-R15-I47-121-0825870 sbin]$ ./nginx -v
    nginx version: nginx/1.4.2
    [admin@A01-R15-I47-121-0825870 sbin]$ 
    

    到此,nginx安装完成。

    nginx.conf配置
        server {
            listen       80;
            server_name  localhost;
    
            #charset koi8-r;
    
            access_log  /export/log/access.log;
            error_log  /export/log/error.log;
    
            location /predict {
                    include         uwsgi_params;
                    uwsgi_pass      unix://export/src/http-cnn-rnn/uwsgi.sock;
            }
    }
    ####主要是location的内容
    
    nginx启动
    sudo /usr/local/nginx/nginx
    sudo /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
    
    重新载入配置文件
    /usr/local/webserver/nginx/sbin/nginx -s reload
    
    重启 Nginx
    /usr/local/webserver/nginx/sbin/nginx -s reopen
    
    停止 Nginx
    /usr/local/webserver/nginx/sbin/nginx -s stop
    

    踩坑

    post数据限制

    安装成功之后,因为需要测试大数据量的POST 的效率,所以发送了一个json数组,差不多50K,然后报错

    The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
    

    很明显,这是因为post的数据量太大了,是flask的限制,在入口方法中添加配置如下:

    from flask import Flask,request,jsonify
    import json
    from cnn_model import TCNNConfig, TextCNN
    from predict import CnnModel
    app = Flask(__name__)
    ###添加以下配置
    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #16MB
    

    相关文章

      网友评论

          本文标题:Flask+UWSGI+Nginx提供在线预测服务

          本文链接:https://www.haomeiwen.com/subject/jgxnpqtx.html