默认情况下lazy-apps的配置是False,uWSGI在第一个进程中加载整个应用程序,并且在加载应用程序之后,它会多次执行fork()本身的操作。可以极大地减少应用程序的内存使用,但也可能招来很多麻烦,比如在存在并发的时候,SQLAlchemy会报错,数据库连接丢失啥的,主要就是这个SQLAlchemy实例在整个app中只创建了一个,看下不配置lazy-apps时的启动代码,各种模块都只创建了一遍,然后才创建worker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ...... *** Operational MODE: preforking *** create app(inc) id:140369684626512 create db id:140369663155112 via <class 'flask_sqlalchemy.SQLAlchemy'> app.api.models models imported app.admin.models models imported install trying app.api app.api.views imported install trying app.admin app.admin.views imported WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x5594c979e200 pid: 21129 (default app) mounting inc:app on / WSGI app 1 (mountpoint='/') ready in 1 seconds on interpreter 0x5594c9e58770 pid: 21129 *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 21129) spawned uWSGI worker 1 (pid: 21130, cores: 1) spawned uWSGI worker 2 (pid: 21131, cores: 1) *** Stats server enabled on 127.0.0.1:3167 fd: 14 *** |
再看看lazy-apps=true时的启动代码,先创建worker,然后各种模块都分别加载了一遍,每个worker的环境是独立的,这样有并发时SQLAlchemy就不会报错了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | *** Operational MODE: preforking *** *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 20980) spawned uWSGI worker 1 (pid: 20981, cores: 1) spawned uWSGI worker 2 (pid: 20982, cores: 1) *** Stats server enabled on 127.0.0.1:3167 fd: 11 *** create app(inc) id:140375376512168 create db id:140375355653144 via <class 'flask_sqlalchemy.SQLAlchemy'> create app(inc) id:140375376512168 create db id:140375355653144 via <class 'flask_sqlalchemy.SQLAlchemy'> app.api.models models imported app.api.models models imported app.admin.models models imported app.admin.models models imported install trying app.api install trying app.api app.api.views imported app.api.views imported install trying app.admin app.admin.views imported install trying app.admin app.admin.views imported WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x560cda997240 pid: 20981 (default app) mounting inc:app on / WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x560cda997240 pid: 20982 (default app) mounting inc:app on / WSGI app 1 (mountpoint='/') ready in 0 seconds on interpreter 0x560cdb051570 pid: 20982 WSGI app 1 (mountpoint='/') ready in 0 seconds on interpreter 0x560cdb051570 pid: 20981 |
想想之前用gunicorn时没发现有这种问题,然后又用gunicorn启动了一下看看有什么不同,当然它没有这个配置项,但它的启动是和lazy-apps=true差不多的,每个worker都是独立的环境,这样虽然占内存,但模块彼此独立,不会再出现资源竞争报错的情况了
参考
https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html?highlight=lazy-apps#preforking-vs-lazy-apps-vs-lazy
https://docs.gunicorn.org/en/latest/settings.html#workers