阅读 63

gunicorn的实践经验

为什么要上gunicorn?

flask自带的web容器不满足生产环境的要求。生产环境不能直接采用flask自带的web容器。

gunicorn是目前应用较广的支持WSGI的web容器。

gunicorn能否替代flask自带的web容器进行开发调试?

可以,加入- -reload,则代码变更后,gunicorn会自动重启。

gunicorn的worker选择gevent时的注意事项

当没有指定worker类型时,默认为同步类型,线程为native类型。

异步worker gevent有很强的并发性能

当worker指定为gevent或evenlet类型时,线程变成基于greentlet的task(伪线程),这时,线程数量的参数是无效的。

采用gevent worker时,默认并发数量是1000,有很强的并发能力。

gevent的兼容性问题

但是,使用gevent时,系统会使用monkey patch。系统的部分函数会被修改。

有些库的使用要选择兼容gevent的类型。

例如,任务调度的库apscheduler,web socket需要socketio的库等,需要专门选择gevent的函数。

而有些库则直接无法使用,例如多进程multiprocess。

例如,在一个api请求中,如果需要使用多核cpu资源,采用multiprocess进行多进程计算。则会出现卡死的问题。gevent中,不能使用multiprocess库

gunicorn的timeout参数

gunicorn默认的timeout时间是30秒,这是满足web应用的典型参数。

但是,我们是深度学习的领域,任务的执行需要的时间很长,所以,timeout参数是一个常用的参数。

gunicorn的管理进程如果在timeout时间内,没有收到worker进程的消息心跳,则会认为worker进程出现了死亡,从而重启相应的worker进程。

会导致worker进程正在执行的任务被中断。

worker进程处于阻塞或高CPU计算时,会出现不能及时发送心跳给管理进程的问题。

因此,对于深度学习领域,timeout要根据业务场景有余量的进行设置,才能保证时间较久的任务不被管理进程中断。

gunicorn什么时候使用- -preload参数

preload

Load application code before the worker processes are forked

默认情况下,gunicorn的每个进程,会将代码重新加载一次,以保障进程之间是互相隔离的。这样可以做到更好的兼容性。

但是,有些情况,需要多个进程共享同一个资源时,或多个进程只能开启1个任务时,则需要使用- -preload

使用preload后,API函数之外的初始化代码,只会出现在gunicorn的管理进程中,以共享的方式让worker进程访问

(这个需要大家自己写demo代码好好体验一下,尤其是初始化变量打印进程号,感知一下preload的差异

可以参考示例:testerhome.com/topics/1830…

思考:gunicorn每个进程在执行log的rotate时的问题。

gunicorn如何集成进程序,不通过命令行进行启动

目前算法采用pyinstaller进行打包,只有一个自启动的执行文件,无法采用传统的gunicorn命令行加载内部代码变量的方式启动。

制作基于gunicorn自启动执行文件,可以参考:docs.gunicorn.org/en/latest/c…

gunicorn的日志问题

我们平时的日志,只记录业务代码的日志。

第三方库的日志和gunicorn自身的日志没有被正常记录在日志文件中,必须在docker的日志里去查看,这样不方便也容易导致丢失或管理不统一。

简单示例代码:

加入gunicorn日志

# 去掉默认的,防止内容和gunicorn重复

logger.removeHandler(default_handler)

# 加入gunicorn的handler

logger.handlers.extend(logging.getLogger(``'gunicorn.error'``).handlers)

# 详细使用参考gunicorn的日志配置部分

或者业务代码的log不变,gunicorn通过配置让其日志单独输出一个文件

web socket的场景

web socket是一个长连接方案,gunicorn默认的同步方式是不支持长连接的。

当使用web socket时,建议独立一个程序,使用异步worker。否则,将它集成到主程序中,会强迫主程序的worker从同步改为异步。

在ops模块中,主程序需要将最新信息推送到web时,可以通过消息队列(ops模块使用的是zeromq)实现进程间的通信,然后通过web socket的独立程序将消息发送到浏览器。

未来,可以尝试ASGI的框架,ASGI是兼容WSGI,同时支持长连接的web socket和http2的推送机制,进一步简化设计。

另外,web socket独立一个程序之后,需要关注其监控问题。

默认的docker启动gunicorn服务,gunicorn服务死亡,docker服务会自动重启。

但是,web socket采用另一个独立的后台进程服务,它的死亡不会导致docker重启。因此,如果web socket进程意外死亡是不会被自动重启的。需要加入监控软件。

官方推荐了很多,目前项目已经使用的有supervisor,使用非常简单。

其他问题

为什么ocr server中,要加入nginx,有什么作用?

正常来说,无需nginx,gunicorn可以正常提供服务。

但是,C++的插件在发送图片给ocr server时,经常会出现witch的错误(目前未知什么原因)。

加入nginx后,无此问题。

(官方推荐使用nginx:Although there are many HTTP proxies available, we strongly advise that you use Nginx.)

文章分类
后端
文章标签