当部署的机器学习模型已经服务于业务时,如何在飞转的引擎下对其进行实时更新,且做到不停机?这是在机器学习应用领域绕不过去的问题,我们知道生产应用中的模型经常会更新,对于营销类的模型变化更快,更新频率经常是小时级或更频繁,那么模型的热部署和版本的自动切换会显得非常关键。
容易想到的方案:只要从POST请求中加载一个新的模型,对不?这看起来是一个简单、合适的方法,但实施关键在理解框架运作原理。
本文将介绍如何让基于Flask应用程序在线更新模型到生产中的步骤。首先,我们将考虑这种方法用于一个单线程的Flask应用程序。接下来,我们将在Web服务器网关接口(WSGI)后面部署它,并发现仍有不足之处。然后,我们将为模型更新添加一个进程锁,以确保在我们的应用程序更新时,其他进程继续提供响应。最后,我们将讨论通过Kubernetes将我们的WSGI进程锁解决方案扩展到多个服务器。
我们需要的不仅仅是一个Flask应用
Flask是最流行的REST API框架之一,可以用于托管机器学习(ML)模型。这一选择在很大程度上受到数据科学团队在Python方面的专业知识和用Python构建的训练资源的可重用性的影响。当前市场上数据科学团队广泛使用 Flask 来服务于各种 ML 模型的预测。然而,在Flask应用为生产准备之前,需要考虑一些问题,比如性能。
如果Flask代码没有被修改为异步运行,那么每次每个进程只能运行一个请求。当您从本地开发扩展到每秒数百个或数千个请求(rps)的生产负载时,这可能会变成一个问题。将Flask应用产品化的第一步是将其置于WSGI后端,WSGI可以生成和管理线程/进程。这篇文章将详细介绍uWSGI的配置,但其他框架也是可用的,如Gunicorn和Gevent。
GIL、线程和进程的入门知识
Python 使用全局解释器锁 (GIL) 来防止多个线程同时执行 Python 字节码。GIL在I/O操作上被释放,包括等待套接字和文件系统的读写。因此,在某些情况下,线程可以带来性能的提升。如果一个操作不重I/O,过多的线程会造成GIL瓶颈。在这种情况下,Python中更高的并发性是通过使用多个并行进程实现的。
将Flask应用程序放置在WSGI后面,将允许您通过进程和/或线程来增加并发性。对于uWSGI,Flask应用程序将根据配置中声明的线程和进程数量进行部署。因为ML预测通常不会从线程中获益,所以我们设置线程数=1,并通过多个进程获得我们的并发性。运行多个进程确实会带来副作用:我们需要为每个进程保留应用内存,而且进程之间不能显式通信(这就意味着模型部署在多个进程的时候,更新模型时需要将每个进程内的模型都要进行更新,否则会出现新模型与旧模型并存的情况)。
模型更新功能结构
生产flask的后端原理:
更新原理
未完待续......